从RAM写入一个大文件到磁盘

时间:2012-08-20 22:10:39

标签: c++ windows-7 file-io

如果我需要从分配的内存到磁盘写一个大文件,那么最有效的方法是什么?

目前我使用了以下内容:

char* data = static_cast<char*>(operator new(0xF00000000)); // 60 GB 

// Do something to fill `data` with data

std::ofstream("output.raw", std::ios::binary).
   write(data, 0xF00000000);

但我不确定最直接的方法是否也是最有效的,考虑到各种缓冲机制等。

我使用的是带有64位目标的Windows 7 64位和Visual Studio 2012 RC编译器。

4 个答案:

答案 0 :(得分:2)

对于Windows,您应该使用CreateFile API。仔细阅读该页面以及提及优化的任何链接。您传递了一些标志来关闭缓冲。我过去是这样做的,当时我以大约每秒800MB的速度收集视频,并且必须尽可能快地将其中的一小部分写入RAID阵列。

现在,对于旗帜 - 我认为主要是这些:

  • FILE_FLAG_NO_BUFFERING
  • FILE_FLAG_WRITE_THROUGH

对于阅读,您可能想要使用FILE_FLAG_SEQUENTIAL_SCAN,但我认为如果关闭缓冲,则无效。

查看Caching Behaviour section

您需要做几件事。首先,您应该始终写入扇区大小倍数的数据量。这几乎是普遍存在(或至少是)512字节,但您可能希望将来考虑最多2048个字节。

其次,您的记忆也必须与该扇区大小对齐。您可以使用_aligned_malloc()或仅分配超出需要的缓冲区并手动对齐。

可能存在其他内存优化问题,您可能希望将单个写入操作限制为内存页面大小。我从来没有深入到那个深度。我仍然能够以非常接近磁盘限制的速度写入数据。它比使用stdio调用快得多。

如果你需要在后台执行此操作,可以使用重叠的I / O,但说实话我从来不理解它。我创建了一个后台工作线程专门写出视频缓冲区并在外部控制它。

答案 1 :(得分:1)

最令人担忧的是输出文件的内存映射。根据数据的填充方式,您甚至可以通过指针将现有程序直接写入磁盘,最后不需要单独的写入步骤。它相信操作系统可以有效地分页文件,无论如何它可能与堆内存有关......可能会避免磁盘到磁盘的复制。

我不确定如何在Windows中专门执行此操作,但您可以通知操作系统您想要的内存访问模式以进一步提高性能。

(boost :: asio具有对内存映射文件的可移植支持)

答案 2 :(得分:1)

如果您想使用std::ofstream,请确保以下内容:

  1. 文件流没有使用缓冲区。这样做的方法是致电out.setbuf(0, 0)
  2. 确保流使用的std::locale不进行任何字符转换,即std::use_facet<std::codecvt<char, char> >(loc).always_noconv()产生true"C"语言环境就是这样做的。
  3. 有了这个,我希望std::ofstream与编写大缓冲区的任何其他方法一样快。我还希望它比使用内存映射I / O慢,因为内存映射I / O应该避免在读取内存时分页内存只是为了编写内容。

答案 3 :(得分:1)

使用CreateFile打开文件,使用SetEndOfFile预分配文件的空间(以避免在写入时出现太多碎片),然后使用2 MB大小的缓冲区调用WriteFile(这个大小在大多数场景中效果最好)在循环中直到你把整个文件写出来。

FILE_FLAG_NO_BUFFERING在某些情况下可能会有所帮助,并且可能会使其他情况变得更糟,因此不需要使用它,因为通常Windows文件系统写缓存正在很好地运行。