在C++中读取12-15GB的ASCII文件的最佳方法

3
我正在尝试计算一个巨大文件中的行数。这个ASCII文件大小在12-15GB之间。目前,我使用类似readline()的方法来计算文件的每一行。但是,这样做非常慢。我也尝试过使用seekg()和tellg()实现更低级别的读取,但由于文件太大,我无法分配足够大的数组来存储每个字符以运行'\n'比较(我只有8GB的RAM)。有没有更快的读取这个超级大文件的方法?我已经查看了许多帖子,大多数人似乎没有遇到32位系统限制的问题,但在这里,我认为这是一个问题(如果我错了,请纠正我)。
此外,如果有人能推荐一种好的方式来拆分这么大的文件,那就太好了。
谢谢!

也许可以进行内存映射,然后快速遍历并计算换行符。 - Kerrek SB
@Kerrek:内存映射会引入特定于平台的代码,需要进行维护。 - Billy ONeal
1
@Billy:当然。但是对于一个15GB的文件,可移植性可能不是你最关心的问题 :-) (明白吗?Portable... :-S)无论如何,我非常想看到内存映射和分块读取之间的性能差异! - Kerrek SB
你具体要做什么?只是想统计行数吗? - Karl Knechtel
@Hans:那不是一个好的思考方式——突然间可能会出现新的固态硬盘,磁盘就不再是瓶颈了,或者一个用户刚刚将文件故障转移到操作系统缓存中,现在你正在尝试进行行计数,或者你必须在RAD期间反复运行一些简单的启动或测试脚本,这些脚本内部需要调用行计数等等... - Tony Delroy
显示剩余2条评论
4个回答

6

不要试图一次性读取整个文件。如果你正在计算行数,只需按给定大小分块读取即可。几兆字节的缓冲区大小应该是合理的。


1
你可能需要进行实验来找到最佳的块大小。我记得几年前它比预期的要小,像不到256K。 - Mark Ransom
1
如果你有SSD,它可能会非常大,我想我之前使用过> 1024K。 - GWW
1
如果您最关心的是速度,则最好错误地使用较大的缓冲区。值得庆幸的是,除非它可能是嵌入式/手机/任何应用程序,否则暂时使用几个MB的堆栈并不重要,并且没有必要尝试准确地达到那个优化点,而收益仅变得不重要。 - Tony Delroy
我不是在为嵌入式设备编写代码,而是尝试实现该方法。但不知何故它读取了比实际存在的更多的 \n 符号。我需要进一步研究这个问题。 - foboi1122

4

3

将文件映射到内存并不需要实际拥有足够的RAM来容纳整个文件。我曾经成功地使用过这种技术来处理高达30 GB的文件(我记得那台机器上有4 GB的RAM)。您需要64位操作系统和64位工具(我在FreeBSD上使用Python)才能够处理这么大的文件。

使用内存映射文件可以显著提高性能,比显式读取文件块要快很多。


如果你无法处理那么多,你仍然可以一次映射文件的较小部分。但我有点困惑为什么提问者会拥有8GB的RAM并担心32位限制。 - Steve Jessop
1
@Steve,也许他们还没有注意到操作系统只使用了3GB。 - Mark Ransom
HxD仅使用少量RAM来读取文件。(它直接从磁盘中读取。) - Mateen Ulhaq
只是稍微扩展一下Greg的最后一点:在Linux上,内存映射可以大大提高性能。然而,在Windows上,情况通常不那么积极(事实上,它通常是较慢的替代方案之一)。至少在我上次测试时,其中一个BSD变体上大致是中性的(尽管我不能确定是哪个)。 - Jerry Coffin
@Steve:我正在编写一个32位应用程序,如果我错了,请纠正我,但这会影响内存使用。 - foboi1122

0
你用的是什么操作系统?这个平台上没有wc -l或类似的命令吗?

1
现在,哪个操作系统可能缺乏这样基本的设施呢……(深思熟虑时挠头);-) - Tony Delroy
非 Windows 系统:for /f %p in (<file>) do @set /a line=line+1 - MSalters
@MSalters:打赌它跑起来像涂了油一样快 :-) - Tony Delroy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接