在C++中高效读取大型文本

9
我需要在C++中读取一个大文本文件(> 10 GB)。这是一个具有可变长度行的csv文件。当我尝试使用ifstream逐行读取时,它可以工作但需要很长时间,我猜这是因为每次读取一行时都要去硬盘上读取,这使得速度非常慢。
有没有一种方法可以缓冲读取,例如一次读取250 MB(使用ifstream的read方法),然后从此缓冲区获取行,我看到了许多解决方案的问题,例如缓冲区可能有不完整的行等等。
在C++中是否有解决这个问题的解决方案,可以处理所有这些情况等等?是否有任何开源库可以做到这一点,例如boost等?
注意:我想避免使用C风格的FILE*指针等。

1
标准库已经使用了缓冲区。由于文件很大,所以需要花费很长时间。也许你正在做其他事情。请发布你使用的代码,我们可以对此进行评论。 - Martin York
4个回答

7
尝试使用Windows内存映射文件功能。调用会被缓冲,您可以将文件视为内存。 内存映射文件

除非环境是64位的,否则将无法将整个10 GB文件映射到一个视图中,因此即使使用这种方法,行边界仍需要像缓冲区一样处理。也就是说,依靠操作系统处理所有I/O并使用内存映射文件进行缓冲仍然很有趣,并且具有出色的性能。 - Suma

3
IOstreams已经使用了缓冲区,与您所描述的类似(尽管通常只有几千字节,而不是数百兆字节)。您可以使用pubsetbuf来使其使用更大的缓冲区,但我不会期望有任何巨大的收益。IOstreams中的大部分开销源于其他领域(例如使用虚拟函数),而不是缺乏缓冲区。
如果您在Windows上运行此代码,则可以通过编写自己的流缓冲区并直接调用CreateFile,传递(例如)FILE_FLAG_SEQUENTIAL_SCANFILE_FLAG_NO_BUFFERING来获得一些性能提升。在这种情况下,其中任何一个都可能极大地提高性能。

3
如果您想要真正的速度,那么您需要停止使用std::string读取行,并开始使用char*读取缓冲区。无论您是使用ifstream::read()还是内存映射文件来读取该缓冲区都不是很重要,但read()有一个缺点,您可能会在缓冲区中遇到N完整行和一个不完整的行,并且需要识别它(可以通过扫描缓冲区中的'\n'来轻松完成 - 可以通过将NUL放在缓冲区之后并使用strchr来完成)。您还需要将部分行复制到缓冲区的起始位置,从文件中读取下一块,以便它继续从该点开始,并更改读取的最大字符数,以使其不会溢出缓冲区。如果您对FILE*感到紧张,我希望您能够熟悉const char*。
由于您提出了这个建议是基于性能原因,我希望您已经进行了测试以确保CSV字段提取等不是真正的瓶颈。

1

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