用 C++ 将数据写入文件 - 最有效的方法?

Posted

技术标签:

【中文标题】用 C++ 将数据写入文件 - 最有效的方法?【英文标题】:Writing data to a file in C++ - most efficient way? 【发布时间】:2014-03-27 16:46:42 【问题描述】:

在我当前的项目中,我正在处理大量数据,这些数据是通过“while”循环在运行时生成的。我想将数据写入 CSV 文件,但我不知道什么更好 - 我应该将所有值存储在向量数组中并在最后写入文件,还是在每次迭代中写入?

我想第一选择更好,但如果可能的话,我想要一个详细的答案。谢谢。

【问题讨论】:

如果你有大量的数据,那么你将需要使用大量的内存来存储在向量中,所以这是一个坏主意。写入文件时也不要使用“endl”,而是使用\n。 @NeilKirk:如果性能真的很重要,fopenfprintf 击败ofstream,然后std::endl 就不再是问题了。 @BenVoigt 为什么,ofstream 有什么问题? @NeilKirk 我猜他可能会担心由于更多的调用和格式化而导致的一些开销,但我仍然更喜欢 I/O 抽象而不是一些毫无意义的性能差异。 @NeilKirk:过度使用互斥锁。由不需要的自定义挂钩引起的虚拟调用。常见实现中的愚蠢。请参阅***.com/questions/4340396/… 底线是ofstream 格式化比大多数现代磁盘驱动器要慢。 【参考方案1】:

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

通过这种方式,您的计算机可以在进行剩余计算的同时开始进行磁盘访问。

PS。不要做任何疯狂的事情,比如每次写入后刷新,或者每次迭代打开和关闭文件。那会降低效率。

【讨论】:

谢谢,我已经想到了这一点。我正在使用ofstream,这是一个不错的选择吗? (我是 C++ 的菜鸟) @Arnaugir: ofstream 确实有缓冲,只要你避开flushendl。但它的开销也比fopen+fprintf 多得多。如果您不需要特定于区域设置的格式(CSV 旨在计算机可读,因此您通常不希望这样做),那么我肯定会建议 fprintf 我认为 CSV 应该是人类可读的。我一直在文本编辑器中编辑它们。 @NeilKirk:CSV 是一种计算机可读的文本格式。作为文本赋予它一些人类可读性。但是计算机可读是限制格式的原因。您不希望将 100456/100 写为 1004,561,004.56。你想忽略区域设置,写1004.56【参考方案2】:

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

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

每次调用写入文件都会产生开销。该开销包括在其目录中的驱动器上定位文件,寻找驱动器上的新位置并写入。写的实际操作相当快;正是这种寻找和等待硬盘驱动器启动并做好准备的过程浪费了您的时间。所以旋转一次,写很多东西让它旋转,然后让它旋转。盘片旋转时写入的数据越多,写入效率就越高。

是的,沿着数据路径到处都有缓存,但是对于大数据量,所有这些都会更有效率。

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

如果你喜欢线程,你可以创建一个线程来监控输出缓冲区。当输出缓冲区达到阈值时,线程将内容写入驱动器。多个缓冲区可以通过让快速处理器填满缓冲区而其他缓冲区写入慢速驱动器来提供帮助。

如果您的平台有 DMA,您可以通过让 DMA 为您写入数据来加快速度。虽然我希望一个好的驱动程序会自动执行此操作。

我确实在嵌入式系统上使用了这种技术,使用 UART(RS232 端口)而不是硬盘驱动器。通过使用缓冲,我可以获得大约 80% 的效率。 (循环展开也可能有帮助。)

【讨论】:

这将最大限度地减少驱动器旋转的总时间,但是当你说“等待硬盘驱动器......浪费你的时间”时你错了。这些是写入。它们被放入写缓冲区,程序愉快地继续进行搜索。写入是异步发生的,无论是使用中断处理程序还是线程并不重要,因为操作系统会处理它。 @BenVoigt:所有缓冲区总是有限制的。在某些时候,处理器花费时间将数据从缓冲区复制到输出端口,通常是通过将执行时间从程序交换到操作系统。具有更快寻道和启动时间的驱动器性能会更好,您的程序也会运行得更快。同样,something 必须监控输出缓冲区。 但是复制到输出端口所花费的时间与驱动器寻道时间完全无关。要么您生成数据的速度超过了磁盘可以接受的速度,在这种情况下,您很自然地会进行大量传输,或者您将一个块传输到磁盘的回写缓冲区,它会旋转并搜索并执行所有需要的物理操作写入数据而不以任何方式打扰您的 CPU,当 CPU 完成下一个块时,它会找到一个空的写回缓冲区来填充。在后一种情况下,寻道时间无关紧要。当然 I/O 库应该被缓冲而不是写入单个字节【参考方案3】:

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

./miProgram > myData.txt

这就是获取程序的输入并放入一个文件中。

对不起英语:)

【讨论】:

以上是关于用 C++ 将数据写入文件 - 最有效的方法?的主要内容,如果未能解决你的问题,请参考以下文章

从套接字读取并写入文件 C++

C++ 如何将一个文件里的数据写入到另一个文件里?

在 C++ 中将数据写入由 CFileDialog 创建的 .txt 文件

如何通过C++ 将数据写入 Excel 工作表

有没有一种最有效的方法来读取/写入C#中的10GB二进制文件?

Spark:排序和分区数据的最有效方法,以拼花形式写入