【发布时间】:2009-08-10 17:06:12
【问题描述】:
我有一个超过 200.000 行的大文本文件,我只需要阅读几行。例如:第 10.000 到 20.000 行。
重要提示:由于性能问题,我不想打开并搜索完整文件以提取这些行。
这可能吗?
【问题讨论】:
-
我已经看到它在 Fortran 中完成,我们必须从数据计数器中读取一个文件(200 万行)。所以我相信这是可行的
我有一个超过 200.000 行的大文本文件,我只需要阅读几行。例如:第 10.000 到 20.000 行。
重要提示:由于性能问题,我不想打开并搜索完整文件以提取这些行。
这可能吗?
【问题讨论】:
如果行是固定长度的,则可以寻找特定的字节位置并仅加载所需的行。如果行是可变长度的,找到您要查找的行的唯一方法是解析文件并计算行尾标记的数量。如果文件不经常更改,您可以通过执行一次此解析然后保留每行的字节位置的索引以加快将来的访问来获得足够的性能(也许将该索引写入磁盘,因此不需要每次运行程序时完成)。
【讨论】:
您必须在文件中搜索以计算换行符,除非您知道所有行的长度相同(在这种情况下,您可以寻找偏移量 = line_number * line_size_in_bytes,其中 line_number 从零开始计数,line_size_in_bytes 包括所有行中的字符)。
如果行是可变/未知长度的,那么在读取它时,您可以索引每行的开始偏移量,以便后续读取可以寻找给定行的开头。
【讨论】:
如果这些行的长度都相同,您可以计算给定行的偏移量并仅读取这些字节。
如果行的长度不同,那么您真的必须阅读整个文件才能计算有多少行。行终止字符只是文件中的任意字节。
【讨论】:
如果线是固定长度,那么你只需计算偏移量,没问题。
如果它们不是(即常规 CSV 文件),则您需要浏览该文件,以构建索引或仅读取您需要的行。为了使文件读取更快一点,一个好主意是使用内存映射文件(请参阅作为 Boost iostreams 一部分的实现:http://www.boost.org/doc/libs/1_39_0/libs/iostreams/doc/classes/mapped_file.html)。
【讨论】:
正如其他人所说,如果您没有固定宽度的线条,则不可能不构建索引。但是,如果您可以控制文件的格式,如果您设法将行号本身存储在每一行,即让文件内容看起来像这样:
1: val1, val2, val3
2: val4
3: val5, val6
4: val7, val8, val9, val10
使用这种格式的文件,你可以通过二分查找快速找到需要的行:从文件中间开始查找。阅读到下一个换行符。然后读取该行,并解析数字。如果数字大于目标,则需要在文件的前半部分重复算法,如果小于目标行号,则需要在文件的后半部分重复。
您需要注意极端情况(例如:范围的“开始”和范围的“结束”在同一行等),但对我来说,这种方法在过去用于解析其中包含日期的日志文件(我需要找到某些时间戳之间的行)。
当然,这仍然比不上显式构建索引或固定大小记录的性能。
【讨论】: