C++14高性能文件读写

8
我正在编写一个C++14程序,从文件中加载文本字符串,对其进行一些计算,然后将结果写入另一个文件。我使用的是Linux系统,并且文件相对较大(O(10^6行))。我的典型方法是使用旧的C中的 getline sscanf 工具来读取和解析输入,以及fprintf(FILE*, ...)来写入输出文件。这种方式虽然可行,但我想知道是否有更好的方法,能够在高性能下运行并符合我所使用的现代C++标准的推荐方式。我听说iostream速度很慢;如果这是真的,我想知道是否有更推荐的方法。
更新:为了更清楚地解释用例:对于输入文件的每一行,我将执行一些文本操作(数据清理等)。每行都是独立进行处理的。因此,加载整个输入文件(或至少其中的大块),逐行处理,然后再将其写入,似乎是最合理的。这个理想的抽象应该是获取一个指向读入缓冲区的迭代器,每行作为一个条目。有没有使用std :: ifstream的推荐方法来做到这一点?

2
根据您访问输入文件的方式(顺序或非顺序),使用文件映射API可能会带来一些好处。不确定在Linux世界中它被称为什么 - 在Windows平台上,我所指的是“CreateFileMapping()”和相关函数。 - BitTickler
1
这取决于您读取的行要做什么(在内存中保留副本还是不保留)以及您正在进行什么类型的解析。最好展示一些片段。此外,这个回答另一个问题可能会对您有所帮助;它没有涉及扫描,但它涉及了一些其他性能方面,并提供了一些基准测试代码的链接。 - Christophe
3
如果你的内存足够,可以一次性将整个文件读入缓冲区中,在内存中处理它,然后再一次性将其全部写出。如果你的内存不够,可以使用内存映射文件 - David
1
我建议不要进行优化,直到您尝试了简单的方法(scanf)并决定它太慢。 - brian beuning
1
@brian:当然,过早优化是万恶之源等等。但我认为在这种情况下并不算过早,因为显然存在性能问题。 - Rudy Velthuis
稍微澄清一下用例:对于输入文件的每一行,我将进行一些文本操作(数据清理等)。每一行都是独立的。因此,加载整个输入文件(或至少是大块),逐行处理,然后写入,似乎是最合理的。这种情况下的理想抽象是获得一个迭代器来读取缓冲区,每一行都是一个条目。是否有一种推荐的方法可以使用std::ifstream实现这一点? - Kulluk007
3个回答

16

如果你有足够的内存,最快的选项是将整个文件一次性读入缓冲区,在内存中处理缓冲区,并使用1次写操作将其全部写出。

全部读取:

std::string buffer;

std::ifstream f("file.txt");
f.seekg(0, std::ios::end);
buffer.resize(f.tellg());
f.seekg(0);
f.read(buffer.data(), buffer.size());

然后处理它

然后把所有内容写入:

std::ofstream f("file.txt");
f.write(buffer.data(), buffer.size());

2
如果文件足够大,并且物理内存的内存压力很高,这段代码最终会从磁盘上读取文件两次。 - IInspectable
3
我认为这是一个“勇敢”的回答,即使不知道文件的绝对大小和可用内存... - Peter VARGA
1
@brianbeuning 和 @Al Bundy,另外,按块(不是 buffer.size() 而是比如每次10000行)读取文件并迭代处理每个块,这样做有什么好处吗? - Kulluk007
3
抱歉 @David,这很好,但不可移植:你无法保证 tellg() 返回的 streampos 可以适应 resize() 期望的 string::size_type - 演示 - Christophe
3
@Christophe,请随意添加numeric_limits检查。 - David
显示剩余3条评论

6
如果您使用的是C++17 (std::filesystem),还可以通过std::filesystem::file_size获取文件大小,而不是使用seekg和tellg。我认为这将允许您避免读取两次。
这在此答案中有所体现。

这个程序如何避免重复读取?使用 seekgtellg 会花费时间来读取整个文件吗? - starriet

1
我认为你可以使用David的方法在并行创建n个线程中读取文件,每个线程都有自己的偏移量,然后将数据拉入单独的区域,再映射到单一位置。请查看ROMIO以获取如何最大化速度的想法。ROMIO的想法可以很容易地在标准C++中实现。

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