在C++中将数据写入文件-最有效的方法是什么?

6
在我的当前项目中,我正在处理大量数据,这些数据是通过“while”循环实时生成的。我想将数据写入CSV文件,但我不知道哪种方法更好 - 是将所有值存储在向量数组中并在最后写入文件,还是每次迭代都写入?
我认为第一个选择更好,但如果可能的话,我希望得到一个详细的答案。谢谢。

如果你有大量的数据,那么你需要使用大量的内存来存储向量,这是一个不好的主意。同时在写入文件时不要使用"endl",而应该使用\n。 - Neil Kirk
如果性能真的很重要,fopenfprintf会比ofstream更快,这时std::endl就不是问题了。 - Ben Voigt
1
@BenVoigt 为什么,ofstream有什么问题吗? - Neil Kirk
@Paranaix:期望会有人不同意10倍性能差异是“毫无意义”的说法。 - Ben Voigt
@BenVoigt 我做了一个快速测试,你是正确的,FILE 比 ofstream 快。但是,在我的机器上,我只注意到 2 倍到 3 倍的因素。 - Neil Kirk
显示剩余8条评论
3个回答

3

确保您使用启用缓冲的I/O库,然后在每次迭代时写入。

这样,您的计算机可以开始与其余计算并行进行磁盘访问。

附注:不要做任何疯狂的事情,例如在每次写入后刷新,或在每次迭代时打开和关闭文件。这会降低效率。


谢谢,我已经考虑过了。我正在使用ofstream,这是一个好选择吗?(我对c++有点新手) - Arnaugir
1
@Arnaugir:只要避免使用flushendlofstream确实具有缓冲功能。但是它的开销比fopen+fprintf大得多。如果您不需要特定于区域设置的格式(CSV旨在供计算机读取,因此通常也不需要),那么我肯定建议使用fprintf - Ben Voigt
我认为CSV应该是人类可读的。我经常在文本编辑器中编辑它们。 - Neil Kirk
@NeilKirk:CSV是一种计算机可读的文本格式。这使它具有一定的人类可读性。但它也因为其计算机可读性而受到一定的限制。你不希望把100456/100写成“1004,56”或“1,004.56”。你需要忽略地区设置,以“1004.56”进行写入。 - Ben Voigt

0

写入文件的最有效方法是减少写操作次数并增加每个操作写入的数据量。

给定一个512字节的字节缓冲区,最低效的方法是一次写入512字节,一次写操作。更有效的方法是进行一次操作以写入512字节。

每次调用写入文件都会有开销。这种开销包括在其目录中定位驱动器上的文件、寻找驱动器上的新位置和写入。实际的写入操作非常快;浪费时间的是寻找并等待硬盘旋转并准备好。因此,让它旋转一次,通过写入大量内容来保持旋转状态,然后让它停止旋转。当盘片旋转时写入的数据越多,写入就越有效率。

  • 是的,数据路径上到处都有缓存,但所有这些都将在大数据大小下更有效率。

我建议将格式化后的内容写入文本缓冲区(即512的倍数),并在某些点将缓冲区刷新到硬盘上。(512字节是硬盘上常见的扇区大小倍数)。

如果你喜欢线程,可以创建一个监视输出缓冲区的线程。当输出缓冲区达到阈值时,线程将内容写入驱动器。多个缓冲区可以通过让快速处理器填充缓冲区,同时将其他缓冲区写入慢速驱动器来提高效率。
如果您的平台具有DMA,您可能可以通过让DMA为您编写数据来加速操作。虽然我希望一个好的驱动程序能够自动完成这项工作。
我在嵌入式系统上使用这种技术,使用UART(RS232端口)代替硬盘。通过使用缓冲,我能够获得约80%的效率。(展开循环也可能有所帮助。)

这将最小化驱动器旋转的总时间,但当你说“等待硬盘...浪费你的时间”时,你是错误的。这些是写入操作。它们被放入写缓冲区中,程序会愉快地继续运行,而寻道操作正在进行。写入操作是异步发生的,无论使用中断处理程序还是线程都不重要,因为操作系统会处理这些事情。 - Ben Voigt
@BenVoigt:所有缓冲区都有限制。在某个时刻,处理器必须花费时间将数据从缓冲区复制到输出端口,通常是通过将执行时间从您的程序交换到操作系统来完成的。具有更快的寻道和启动时间的驱动器将表现更好,您的程序将运行更快。再次强调,某些东西必须监视输出缓冲区。 - Thomas Matthews
但是将数据复制到输出端口所花费的时间与驱动器寻道时间完全无关。如果您生成的数据比磁盘接受的速度快,那么您自然会得到大量的传输;或者,您将一个块传输到磁盘的写回缓冲区中,它会旋转、寻道并执行所有需要写入数据的物理操作,而不会以任何方式打扰您的 CPU,当 CPU 完成下一个块时,它会找到一个空的写回缓冲区来填充。在后一种情况下,寻道时间并不重要。当然,I/O 库应该是缓冲的,而不是写单个字节。 - Ben Voigt

-1

最简单的方法是在控制台中使用 > 运算符。在 Linux 中:

./miProgram > myData.txt

这将获取程序的输入并将其放入文件中。

对于英语不好的人表示抱歉 :)


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