user-0 提问: C语言从一个文件中读取乱序内容，并排序，数据量比较大怎么弄？谢谢

回复:
user: user-1
content: 1、内存足够，读一次文件，所有数据排序，再写新文件，是最快的，比逐个读记录边读边插入肯定快。 2、我说的先提取排序关键字和偏移，排序后再读取再写入，是2次文件读取1次写，是慢一点，但是可以对付内存不够放下整个文件的情况。 3、至于排序的关键字不是记录的首字节，并不是很麻烦的事情，偏移是该条记录的首字节对应在文件中的位置，是需要解析记录再获取的。如果记录不等长，还需要一个字段记录该条记录的长度。 4、操作系统读文件，如果读某个偏移开始的位置，应该不是从头开始读磁盘的，可以根据文件分配表的内容，直接找到该偏移对应的物理扇区。不是偏移量越大，每次读取的时间越长。

user: user-2
content: 这样第一条记录就是id为1的记录了

user: user-2
content: 引用 25 楼 sys0613 的回复:[quote=引用 23 楼 xg436 的回复:] 又看了一遍，你是可以直接缓存A中所有数据？那就新建个数组，和字符串数组，第一条的id是100，那就int【100】=1，string【0】=内容，然后写b就string【int【i++】】 完全没看懂，缓存了不是还要排序么？[/quote] 不需要了 比如A里的ID依次为35214，存储到str[]里面，那么你按我说的int数组里int[1,2,3,4,5]对应的是[4,3,1,5,2]，然后str[int[1]]=str[4]=1

user: user-3
content: 命令提示实用工具    bcp 实用工具 bcp 实用工具在 Microsoft® SQL Server™ 2000 实例和数据文件之间以用户指定的格式复制数据。  语法 bcp {[[database_name.][owner].]{table_name | view_name} | "query"}     {in | out | queryout | format} data_file     [-m max_errors] [-f format_file] [-e err_file]     [-F first_row] [-L last_row] [-b batch_size]     [-n] [-c] [-w] [-N] [-V (60 | 65 | 70)] [-6]     [-q] [-C code_page] [-t field_term] [-r row_term]     [-i input_file] [-o output_file] [-a packet_size]     [-S server_name[\instance_name]] [-U login_id] [-P password]     [-T] [-v] [-R] [-k] [-E] [-h "hint [,...n]"]  参数database_name  指定的表或视图所在数据库的名称。如果未指定，则为用户默认数据库。  owner  表或视图所有者的名称。如果执行大容量复制操作的用户拥有指定的表或视图，则 owner 是可选的。如果没有指定 owner 并且执行大容量复制操作的用户不拥有指定的表或视图，则 Microsoft® SQL Server™ 2000 将返回错误信息并取消大容量复制操作。  table_name  是将数据复制到 SQL Server 时 (in) 的目的表名，以及从 SQL Server 复制数据时 (out) 的源表名。  view_name  是将数据复制到 SQL Server 时 (in) 的目的视图名，以及从 SQL Server 复制数据时 (out) 的源视图名。只有其中所有列都引用同一个表的视图才能用作目的视图。有关将数据复制到视图的限制的更多信息，请参见 INSERT。  Query  是返回一个结果集的 Transact-SQL 查询。如果查询返回多个结果集，例如指定 COMPUTE 子句的 SELECT 语句，只有第一个结果集将复制到数据文件，随后的结果集被忽略。使用双引号引起查询语句，使用单引号引起查询语句中嵌入的任何内容。在从查询中大容量复制数据时，还必须指定 queryout。  in | out | queryout | format  指定大容量复制的方向。in 是从文件复制到数据库表或视图，out 是指从数据库表或视图复制到文件。只有从查询中大容量复制数据时，才必须指定 queryout。根据指定的选项（-n、-c、-w、-6 或 -N）以及表或视图分隔符，format 将创建一个格式文件。如果使用 format，则还必须指定 -f 选项。    说明  Microsoft SQL Server 6.5 中的 bcp 实用工具不支持大容量复制到包含 sql_variant 或 bigint 数据类型的表。   data_file  大容量复制表或视图到磁盘（或者从磁盘复制）时所用数据文件的完整路径。当将数据大容量复制到 SQL Server 时，此数据文件包含将复制到指定表或视图的数据。当从 SQL Server 大容量复制数据时，该数据文件包含从表或视图复制的数据。路径可以有 1 到 255 个字符。  -m max_errors  指定在大容量复制操作取消之前可能产生的错误的最大数目。bcp 无法复制的每一行都将被忽略并计为一个错误。如果没有包括该选项，则默认为 10。  -f format_file  指定格式文件的完整路径，该格式文件包含以前在同一个表或视图上使用 bcp 时的存储响应。当使用由 format 选项所创建的格式文件大容量复制入或复制出数据时，使用此选项。格式文件的创建是可选的。在提示几个格式问题之后，bcp 将提示是否在格式文件中保存回答。默认文件名为 Bcp.fmt。大容量复制数据时，bcp 可引用一个格式文件，因此不必重新交互输入以前的回答。如果未使用此选项，也没有指定 –n、-c、-w、-6 或 -N，则 bcp 将提示输入格式信息。  -e err_file  指定错误文件的完整路径，此错误文件用于存储 bcp 无法从文件传输到数据库的所有行。来自 bcp 的错误信息将发送到用户工作站。如果未使用此选项，则不创建错误文件。  -F first_row  指定要大容量复制的第一行的序数。默认值是 1，表示在指定数据文件的第一行。  -L last_row  指定要大容量复制的最后一行的序数。默认值是 0，表示指定数据文件中的最后一行。  -b batch_size  指定所复制的每批数据中的行数。每个批处理作为一个事务复制至服务器。SQL Server 提交或回滚（在失败时）每个批处理的事务。默认情况下，指定的数据文件中的所有数据都作为一批复制。请不要与 -h "ROWS_PER_BATCH = bb" 选项一起使用。  -n  使用数据的本机（数据库）数据类型执行大容量复制操作。此选项不提示输入每一字段，它将使用本机值。  -c  使用字符数据类型执行大容量复制操作。此选项不提示输入每一字段；它使用 char 作为存储类型，不带前缀，\t（制表符）作为字段分隔符，\n（换行符）作为行终止符。  -w  使用 Unicode 字符执行大容量复制操作。此选项不提示输入每一字段；它使用 nchar 作为存储类型，不带前缀，\t（制表符）作为字段分隔符，\n（换行符）作为行终止符。不能在 SQL Server 6.5 版或更早版本中使用。  -N  对非字符数据使用数据的本机（数据库）数据类型和对字符数据使用 Unicode 字符类型执行大容量复制操作。这是可替代 -w 选项的性能更高的选项，其目的是使用数据文件将数据从一个 SQL Server 传输到另一个 SQL Server 中。它不提示输入每一字段。在需要传输包含 ANSI 扩展字符的数据以及想利用本机模式的性能时，可以使用这一选项。不能在 SQL Server 6.5 版或更早版本中使用 -N 选项。  -V (60 | 65 | 70)  使用 SQL Server 早期版本中的数据类型执行大容量复制操作。此选项与字符 (-c) 或本机 (-n) 格式一起使用。此选项并不提示输入每一字段，它使用默认值。例如，若要将 SQL Server 6.5 中的 bcp 实用工具所支持（但 ODBC 不再支持）的日期格式大容量复制到 SQL Server 2000，可使用 -V 65 参数。    重要  将数据从 SQL Server 大容量复制到数据文件时，即使指定了 –V，bcp 实用工具也不会为任何 datetime 或 smalldatetime 数据生成 SQL Server 6.0 或 SQL Server 6.5 的日期格式。日期将始终以 ODBC 格式写入。另外，由于 SQL Server 6.5 版或更早版本不支持可为空的 bit 数据，因此 bit 列中的空值写为值 0。   -6  使用 SQL Server 6.0 或 SQL Server 6.5 数据类型执行大容量复制操作。仅为保持向后兼容性。改为使用 –V 选项。  -q  在 bcp 实用工具和 SQL Server 实例的连接中执行 SET QUOTED_IDENTIFIERS ON 语句。使用该选项指定包含空格或引号的数据库、所有者、表或视图的名称。将由三部分组成的整个表名或视图名引在双引号 (" ") 中。  -C code_page  仅为保持向后兼容性。作为代替，请在格式文件或交互式 bcp 中为每一列指定一个排序规则名。  指定数据文件中的数据代码页。只有当数据中包含字符值大于 127 或小于 32 的 char、varchar 或 text 列时，code_page 才有用。  代码页值 描述  ACP ANSI/Microsoft Windows® (ISO 1252)。  OEM 客户程序使用的默认代码页。如果未指定 -C，则这是 bcp 使用的默认代码页。  RAW 不发生从一个代码页到另一个代码页的转换。因为不发生转换，所以这是最快的选项。  <值> 特定的代码页号码，例如 850。    -t field_term  指定字段终止符。默认的字段终止符是 \t（制表符）。使用此参数替代默认字段终止符。  -r row_term  指定行终止符。默认的行终止符是 \n（换行符）。使用此参数替代默认行终止符。  -i input_file  指定响应文件的名称，使用交互模式（未指定 –n、-c、-w、-6 或 -N）执行大容量复制时，响应文件包含对每一字段命令提示问题的响应。  -o output_file  指定接收 bcp 输出（从命令提示重定向）的文件的名称。  -a packet_size  指定发送到和发送自服务器的每个网络数据包的字节数。可以使用 SQL Server 企业管理器（或 sp_configure 系统存储过程）设置服务器配置选项。但是，使用此选项可以单个地替代服务器配置选项。packet_size 可以设置为 4096 到 65535 字节，默认值为 4096。  数据包大小的增加能够提高大容量复制操作的性能。如果要求一个较大的数据包而得不到，则使用默认设置。bcp 生成的性能统计显示出所使用数据包的大小。  -S server_name[\instance_name]  指定要连接到的 SQL Server 实例。指定 server_name 以连接该服务器上的 SQL Server 默认实例。指定 server_name\instance_name 以连接到该服务器上的 SQL Server 2000 命名实例。如果未指定服务器，则 bcp 连接到本地计算机上的 SQL Server 默认实例。从网络上的远程计算机执行 bcp 时，要求此选项。  -U login_id  指定用于连接到 SQL Server 的登录 ID。  -P password  指定登录 ID 的密码。如果未使用此选项，则 bcp 将提示输入密码。如果不带密码将此选项用于命令提示行末尾，则 bcp 将使用默认密码 (NULL)。  -T  指定 bcp 使用网络用户的安全凭据，通过信任连接连接到 SQL Server。不需要 login_id 和 password。  -v  报告 bcp 实用工具的版本号和版权。  -R  指定使用为客户端计算机的区域设置定义的区域格式，将货币、日期和时间数据大容量复制到 SQL Server 中。默认情况下，将会忽略区域设置。  -k  指定在大容量复制操作中空列应保留一个空值，而不是对插入的列赋予默认值。  -E  指定标识列的值出现在要导入的文件中。如果没有给出 -E，则正导入的数据文件中此列的标识值将被忽略，而且 SQL Server 2000 会根据创建表期间指定的种子值和增量值自动指派唯一的值。如果数据文件的表或视图中不包含标识列的值，则使用格式文件指定导入数据时应跳过表或视图中的标识列；SQL Server 2000 将自动为该列指派唯一值。有关详细信息，请参见 DBCC CHECKIDENT。  -h "hint [,...n]"  指定在大容量复制数据到表或视图时所使用的提示。在大容量复制数据到 SQL Server 6.x 或更早版本时，不能使用此选项。  提示 描述  ORDER (column [ASC | DESC] [,...n]) 数据文件中数据的排序次序。如果要装载的数据已根据表中的聚集索引排序，则会提高大容量复制的性能。如果数据文件按不同次序排序，或者该表没有聚集索引，则将忽略 ORDER 提示。所提供的列名必须是目的表中的有效列。默认情况下，bcp 假设数据文件没有排序。  ROWS_PER_BATCH = bb 每批中数据的行数（即 bb）。在未指定 -b 时使用，这将使整个数据文件作为单个事务发送到服务器。服务器根据值 bb 优化大容量装载。默认情况下，ROWS_PER_BATCH 未知。  KILOBYTES_PER_BATCH = cc 每批中数据的千字节 (KB) 近似数量（即 cc）。默认情况下，KILOBYTES_PER_BATCH 未知。  TABLOCK 大容量复制操作期间将获取表级锁。由于只在大容量复制操作期间才控制锁减少了表中锁的争夺，因此此提示可以显著提高性能。如果表没有索引并且指定了 TABLOCK，则该表可以同时由多个客户端装载。默认情况下，锁定行为是由表选项 table lock on bulk load 决定的。  CHECK_CONSTRAINTS 大容量复制操作期间，将检查目的表上的所有约束。默认情况下，将会忽略约束。  FIRE_TRIGGERS 与 in 参数一起指定，在目的表上定义的任何插入触发器将在大容量复制操作期间执行。如果没有指定 FIRE_TRIGGERS，则不执行插入触发器。对于 out、queryout 和 format 参数，将忽略 FIRE_TRIGGERS。    注释 将忽略要导入的数据文件中计算列或 timestamp 列的值，SQL Server 2000 自动赋值。如果数据文件不包含表中的计算列或 timestamp 列的值，可用格式文件指定应在导入数据时跳过表中的计算列和 timestamp 列；SQL Server 将自动为该列赋值。  计算列和 timestamp 列照常会从 SQL Server 大容量复制到一个数据文件。  SQL Server 标识符（包括数据库名称、表名或视图名、登录和密码）可以包含诸如嵌入空格和引号等字符。当在命令提示符处指定包含空格或引号的标识符或文件名时，需要将该标识符引在双引号 (" ") 内。另外，对于包含嵌入空格或引号的所有者、表或视图的名称，可以指定 -q 选项，或者将所有者、表或视图的名称在双引号内用方括号 ([ ]) 括起来。  例如，Northwind 数据库内有表 Jane's Orders，该表由用户 Jane Doe 所拥有。若要使用登录 Jane Doe 和密码 go dba 将该表从 Northwind 数据库大容量复制到 Orders.txt 文件，请执行下列命令之一：  bcp "Northwind.Jane Doe.Jane's Orders" out "Jane's Orders.txt" -c -q -U"Jane Doe" -P"go dba"  bcp "Northwind.[Jane Doe].[Jane's Orders]" out "Jane's Orders.txt" -c -U"Jane Doe" -P"go dba"  若要指定包含空格或引号的数据库名称，必须使用 -q 选项。  有关此实用工具位置和运行方式的信息，请参见命令提示实用工具入门。   请参见  在不同排序规则间复制数据  使用 bcp 和 BULK INSERT  并行数据装载  SET QUOTED_IDENTIFIER  sp_tableoption  使用格式文件  ©1988-2000 Microsoft Corporation。保留所有权利。   管理 SQL Server     指定数据格式 如果正在 Microsoft® SQL Server™ 实例和其它程序（例如另一个数据库程序）之间复制数据，则默认的数据类型格式（本机、字符或 Unicode）可能与其它程序所预期的数据结构不兼容。因此，bcp 实用工具允许指定有关数据文件结构的更详细的信息。  如果没有指定 -n、-c、-w 或 -N 开关，则 bcp 实用工具会交互式地提示输入正在复制的每个列的进一步信息：   文件存储类型   前缀长度   字段长度   字段终止符    说明  在使用 BULK INSERT 语句时不能使用交互模式。  根据源列或目的列的 SQL Server 数据类型，bcp 实用工具在每个提示中都会提供默认值。接受 bcp 在这些提示中提供的默认值将生成与本机格式 (-n) 相同的结果，并提供一种方法，以将数据从其它程序中大容量复制出来，以便日后重新装载到 SQL Server 中。  可以创建一个格式文件，用来存储对数据文件各字段的提示的响应，以便重复使用相同的响应而不必再次输入它们。格式文件可以提供将数据大容量复制到 SQL Server 实例，或从 SQL Server 实例大容量复制数据时所需的所有格式信息。格式文件提供了一种灵活的系统，用来写入很少需要或不需要编辑即可符合其它数据格式的数据文件，或者用来从其它软件中读取数据文件。  例如，若要交互式地将 publishers 表大容量复制到 Publ.txt 文件中，可以使用以下命令：  bcp pubs..publishers out publ.txt -Sservername -Usa -Ppassword  对 publishers 表的每一列，都会出现四个提示，并且在方括号中显示 bcp 提供的默认值。以下示例只是 publishers 表中 pub_id 列的情况。  Enter the file storage type of field pub_id [char]: Enter prefix length of field pub_id [0]: Enter length of field pub_id [4]: Enter field terminator [none]:  按 ENTER 键接受所提供的默认值。若要指定与默认值不同的值，请在命令提示符下输入新值。   请参见  使用格式文件  ©1988-2000 Microsoft Corporation。保留所有权利。

user: user-0
content: 引用 23 楼 xg436 的回复:又看了一遍，你是可以直接缓存A中所有数据？那就新建个数组，和字符串数组，第一条的id是100，那就int【100】=1，string【0】=内容，然后写b就string【int【i++】】 完全没看懂，缓存了不是还要排序么？

user: user-0
content: 引用 15 楼 ananluowei 的回复:先读取每条记录的id，记下这条记录在文件中的偏移，用一个结构保存这2个数据。读完整个文件，对这个结构的数组排序。 根据排序后的内容，逐条id读取每条记录，存到新文件。 还有个问题，如果id不是每个数据结构的第一个，这个id是没用的，无法计算偏移的。。。可能id是第6个属性，前五个属性长度无法确定，所以是找不到文件偏移的，是吧？？如果找不到的话，这个偏移就不行吧？谢谢  引用 21 楼 zhao4zhong1 的回复:参考SQL Server中的bcp命令行工具。 数据有规律，就能导入进数据库？谢谢

user: user-2
content: 又看了一遍，你是可以直接缓存A中所有数据？那就新建个数组，和字符串数组，第一条的id是100，那就int【100】=1，string【0】=内容，然后写b就string【int【i++】】

user: user-2
content: 不想用数据库就用文件代替吧。 你的文件是1G的，最大的id是一百万。然后新建100个文本，标记为1-100，然后新建100个字符串，然后读A，id在1-1w的加到第一个字符串里面，id在1-2w的写到第二个...，内存到上限了就写到对应的文本里去。读取完以后，读取文件1到缓存，排序，写到B里，然后是文件2.3.4..。

user: user-3
content: 参考SQL Server中的bcp命令行工具。

user: user-0
content: 引用 13 楼 hongwenjun 的回复:放出 示例的 几行出来看下，可以用不相关 代替文字信息 您是想从数据上找规律么？呵呵，数据上不是按照行分的，例如数据就是，head：id:001 内容：abc 语言：英语 end head：id:002 内容：abc 语言：汉语 end，就是这么一个挨着一个的，通过head头和end尾区分，head和end中间夹着的内容属性一样，没有换行区分。属性我这举例子就3个，实际每个属性也是10几个。

user: user-0
content: 引用 15 楼 ananluowei 的回复:先读取每条记录的id，记下这条记录在文件中的偏移，用一个结构保存这2个数据。读完整个文件，对这个结构的数组排序。 根据排序后的内容，逐条id读取每条记录，存到新文件。 谢谢了，我想问下如果文件很大的话，再次找到这个偏移时候会不会很慢？？再就是对id排序和对从文件中读取的整个数据进行排序，效率上会有很大提升么？感谢了

user: user-0
content: 引用 14 楼 hdt 的回复:几十万条数据，估计一二百兆，不想用数据库，可以用内存映射文件 具体请查msdn目前就是用的内存映射文件，读取文件这里的速度应该可以了

user: user-4
content: 我电脑里所有文件 的 全路径 记录 24.66万， list.txt  15.5M 排序的时间

user: user-4
content: http://bbs.csdn.net/topics/380117760  #include <iostream> #include <string> #include <vector> #include <algorithm> #include <cstring> #include <cctype> #include <fstream> #include <sstream>  #define WIN32 //VC 编译器开关 #include <time.h> #ifdef WIN32 #   include <windows.h> #else #   include <sys\time.h> #endif #ifdef WIN32 int gettimeofday(struct timeval* tp, void* tzp) {     time_t clock;     struct tm tm;     SYSTEMTIME wtm;     GetLocalTime(&wtm);     tm.tm_year     = wtm.wYear - 1900;     tm.tm_mon     = wtm.wMonth - 1;     tm.tm_mday     = wtm.wDay;     tm.tm_hour     = wtm.wHour;     tm.tm_min     = wtm.wMinute;     tm.tm_sec     = wtm.wSecond;     tm. tm_isdst    = -1;     clock = mktime(&tm);     tp->tv_sec = clock;     tp->tv_usec = wtm.wMilliseconds * 1000;     return (0); } #endif /* WIN32 */ using std::stringstream; using std::vector; using std::string; using std::fstream; void help(); // 调用使用帮助 bool isdigit(const std::string& str); // overload function  重载函数 bool isalpha(const std::string& str); stringstream& load_sstream(stringstream& oss, fstream& infile);  // 加载文件到sstream vector<string> & sortVecData(vector<string> & vecData); // 排序和删除重复   int main(int argc, char* argv[]) {     using namespace std;     if ((1 == argc) || (2 == argc)) {    //错误输入处理         help();         return -1;     }     string Value = argv[1];     fstream inFile;     inFile.open(argv[2], ios_base::in);     if (!inFile) {         cerr << "文件错误：不能打开输入文件: " << argv[2] << endl << endl ;         help();         return -1;     }     bool sortData = false;     // 排序开关     if (argc >= 4 && ('s' == argv[3][1] || 'S' == argv[3][1])) {         sortData = true;     }       stringstream oss;     ofstream ofDataFile;     ofDataFile.open("LineData.txt"); //保存到 新的数据档文件     long ixold = 0, ixnew = 0;     string::size_type pos;     string  strLine;     vector<string> vecLine;     cout << "当前搜索关键字：" << Value << endl;     // 取时间断点     timeval tv;     gettimeofday(&tv, NULL);     double cl = tv.tv_sec + (double)tv.tv_usec / 1000000;       while (getline(inFile , strLine)) {  // 整行处理，数据文件 数据输入         if (strcmp(argv[1] , "ALL")  == 0 ) {   // 所有数据排序用             vecLine.push_back(strLine);         } else {             pos = strLine.find(Value);             if (pos != string::npos) {                 vecLine.push_back(strLine);      //数据记录到容器             }         }           ixold++;  // 旧数据计数器         if (ixold % 100000 == 0) cout << ">";     }       gettimeofday(&tv, NULL);     cl = (tv.tv_sec + (double)tv.tv_usec / 1000000) - cl;     cout << "\n原来数据记录数目：" << ixold << "\t";     cout << "新的数据记录数目：" << vecLine.size() << endl;     cout << "提取数据花费时间：" << cl << " 秒\n";       if (sortData) {  // 判断排序         cout << "正在排序优化中，请等候....\n";         gettimeofday(&tv, NULL);         cl = tv.tv_sec + (double)tv.tv_usec / 1000000;           sortVecData(vecLine);  //数据排序 删除重复         cout << "排序优化后数据量：" << vecLine.size() << "\t";         gettimeofday(&tv, NULL);         cl = (tv.tv_sec + (double)tv.tv_usec / 1000000) - cl;         cout << "排序数据花费时间：" << cl << " 秒\n";     }     cout << "正在把数据写到新文件中......\t如果数据重复,可以最后加参数 -S 优化排序\n" ;     gettimeofday(&tv, NULL);     cl = tv.tv_sec + (double)tv.tv_usec / 1000000;     vector<string>::iterator iter = vecLine.begin();     while (iter != vecLine.end()) {         oss << *iter++ << endl;  // 数据写到缓存流         if (ixnew++ % 100000 == 0) cout << "<";    //新数据计数器     }     ofDataFile << oss.str();   // 缓冲区写文件     gettimeofday(&tv, NULL);     cl = (tv.tv_sec + (double)tv.tv_usec / 1000000) - cl;     cout << "保存新数据文件花费时间：" << cl << " 秒\n";     cout << "\n已经生成新的包含关键字的数据文件 LineData.txt" << endl;     inFile.close();     ofDataFile.close();     return 0; } // overload function  重载函数 isdigit bool isdigit(const std::string& str) {     bool flag = true;     for (std::string::size_type i = 0; i < str.length(); i++) {         while (!isdigit(str[i])) {             flag = false;             break;         }     }     return flag; } bool isalpha(const std::string& str) {     bool flag = true;     for (std::string::size_type i = 0; i < str.length(); i++) {         while (!isalpha(str[i])) {             flag = false;             break;         }     }     return flag; } void help() {     using std::cerr;     cerr << "本工具可以从文件中按关键字搜索数据行 并且有排序功能 [版本 0.98] BY Hong Wenjun\n\n";     cerr << "示例 1 ：D:\\>LineExtraction.exe  \"关键字\"  D:\\原始数据.txt  \n" ;     cerr << "示例 2 ：D:\\>LineExtraction.exe  \"关键字\"  D:\\原始数据.txt  -S\n" ;     cerr << "示例 3 ：D:\\>LineExtraction.exe    ALL     D:\\原始数据.txt  -S\n\n" ;     cerr << "请输入一个关键字！！[ \"关键字\"    ALL    ] 按两种方式选择一种\n";     cerr << "ALL 关键字  提取所有数据，和-S参数配合排序\n";     cerr << "-S  参数   排序优化，删除重复数据\n"; }   stringstream& load_sstream(stringstream& oss, fstream& infile)  // 加载文件到sstream {     oss << infile.rdbuf();     return oss; }   vector<string> & sortVecData(vector<string> &vecData) // 排序和删除重复 数字序列 {     sort(vecData.begin(), vecData.end());  //数据排序     vector<string>::iterator end_unique = unique(vecData.begin(), vecData.end());  // 移动重复到最后     vecData.erase(end_unique, vecData.end());  //删除重复     return vecData; }  看你的文件多大    280M的 600W记录某站 数据档，使用这个程序所有记录排序 写文件时，使用大内存缓冲，代价是多使用1G内存

user: user-1
content: 先读取每条记录的id，记下这条记录在文件中的偏移，用一个结构保存这2个数据。读完整个文件，对这个结构的数组排序。 根据排序后的内容，逐条id读取每条记录，存到新文件。

user: user-5
content: 几十万条数据，估计一二百兆，不想用数据库，可以用内存映射文件 具体请查msdn

user: user-4
content: 放出 示例的 几行出来看下，可以用不相关 代替文字信息

user: user-6
content: 引用 10 楼 sys0613 的回复:[quote=引用 8 楼 cfjtaishan 的回复:] [quote=引用 5 楼 sys0613 的回复:] [quote=引用 2 楼 cfjtaishan 的回复:] 如果将所有的数据从文件里读取，然后再排序，确实很占内存，数据项目多，排序也会比较耗时。 是否可以根据ID的特点，比如ID是从1到多少，先从文件里读，若读到ID为1的，则写入B文件，读到ID位2的写入文件，然后记录一下目前B文件里的ID号，每次写B文件前，先从内存里查找是否已经符合写文件的ID，若没有继续从A文件里读，若读到直接写B文件，若没有继续读； 比如,读到的ID信息的顺序是 3 4 7 8 1，此时将ID位1的信息写入B文件，记录目前B文件里的ID，接下来从已经读到的缓存里查找2，若没有继续从文件里读；知道读到ID为2，写入B文件，然后从已经读到的文件里查找3。。。 这样的好处是，可以减少内存里的消耗，还能减少排序的耗时，但是有个缺点，ID需要符合已经规律； 根据你的ID信息来确定我的方法是否可行了。 谢谢您了，我这个id很大可能是倒序，如果先都存到内存中，每轮进到内存中去扫描，还是相当于将剩下数据扫描了一遍吧？这种场景是不是就效率没变啊？[/quote] 要看你的文件里ID是否位倒序，如果是完全的倒序那么效率没怎么提高 如果是完全的倒序，如果占用内存很多，想用时间换空间，可以考虑写入多个文件，每个文件是有序的。最后再将文件集中到一个文件里。这个会比较麻烦，但也是一种办法[/quote]  谢谢您了，我现在是想用空间换时间，目前执行的太慢了[/quote] 我说反了，写入多个文件是以空间换时间；数据量大，排序会很占时间，另外，你的数据放在局部数组里还是全局数组或者在堆上申请的空间，另外，你的排序是用什么方法，可以考虑用快排或者堆排实现

user: user-0
content: 引用 9 楼 hdt 的回复:[quote=引用 7 楼 sys0613 的回复:] [quote=引用 6 楼 hdt 的回复:] 个人感觉这样的情况还是把数据导入到数据库里面处理比较好！ 就是将文件中的数据都存到数据库中，然后利用数据库进行排序？因为这个id只是一条数据中的一项，一条数据有好多属性，id只是作为排序的关键字了。 唉，不知道不用数据库的话能不能提高点效率呢。好尴尬。今天跑70w数据，直接就没看到结束。。强制停止了。。。[/quote] 如果文本文件的格式比较规范，完全可以通过数据库自带的工具导入到数据库中。几十万数对于像oracle,mssql之类数据库，完全是小case[/quote] 现在是想用最少的软件来完成此项工作，两个文件的交互不想带上数据库。如果纯两个文件来排序，不用数据库的话有什么更好的办法么？谢谢了

user: user-0
content: 引用 8 楼 cfjtaishan 的回复:[quote=引用 5 楼 sys0613 的回复:] [quote=引用 2 楼 cfjtaishan 的回复:] 如果将所有的数据从文件里读取，然后再排序，确实很占内存，数据项目多，排序也会比较耗时。 是否可以根据ID的特点，比如ID是从1到多少，先从文件里读，若读到ID为1的，则写入B文件，读到ID位2的写入文件，然后记录一下目前B文件里的ID号，每次写B文件前，先从内存里查找是否已经符合写文件的ID，若没有继续从A文件里读，若读到直接写B文件，若没有继续读； 比如,读到的ID信息的顺序是 3 4 7 8 1，此时将ID位1的信息写入B文件，记录目前B文件里的ID，接下来从已经读到的缓存里查找2，若没有继续从文件里读；知道读到ID为2，写入B文件，然后从已经读到的文件里查找3。。。 这样的好处是，可以减少内存里的消耗，还能减少排序的耗时，但是有个缺点，ID需要符合已经规律； 根据你的ID信息来确定我的方法是否可行了。 谢谢您了，我这个id很大可能是倒序，如果先都存到内存中，每轮进到内存中去扫描，还是相当于将剩下数据扫描了一遍吧？这种场景是不是就效率没变啊？[/quote] 要看你的文件里ID是否位倒序，如果是完全的倒序那么效率没怎么提高 如果是完全的倒序，如果占用内存很多，想用时间换空间，可以考虑写入多个文件，每个文件是有序的。最后再将文件集中到一个文件里。这个会比较麻烦，但也是一种办法[/quote]  谢谢您了，我现在是想用空间换时间，目前执行的太慢了