【问题标题】:Creating big file on Windows在 Windows 上创建大文件
【发布时间】:2010-10-02 02:27:03
【问题描述】:

我需要创建相对较大 (1-8 GB) 的文件。在 Windows 上使用 C 或 C++ 最快的方法是什么?我需要即时创建它们,速度确实是个问题。文件将用于存储仿真,即以不同的偏移量随机访问,我需要所有存储都将预先分配但未初始化,目前我们正在使用虚拟数据写入所有存储,并且花费的时间太长。

谢谢。

【问题讨论】:

    标签: c windows file file-io


    【解决方案1】:

    使用 Win32 API,CreateFileSetFilePointerExSetEndOfFileCloseHandle。以同样的顺序。

    诀窍在于 SetFilePointerEx 函数。来自 MSDN:

    注意,设置不是错误 指向超出位置的文件指针 文件的结尾。的大小 文件不会增加,直到您调用 SetEndOfFile、WriteFile 或 WriteFileEx 函数。

    在将文件从一个位置复制到另一个位置时,Windows 资源管理器实际上会做同样的事情。这样做是为了使磁盘不需要为碎片磁盘重新分配文件。

    【讨论】:

    • 这只会在 NTFS 和 exFAT 上快速运行,而不是在 FAT32、FAT16 上。这是因为这些文件系统具有“初始化大小”
    • SetEndOfFile() 在写入文件时会导致严重的延迟。如果您写入文件的中间,Windows 会将所有尚未写入的块清零,直到写入的位置。见blogs.msdn.com/b/oldnewthing/archive/2011/09/22/10215053.aspx(我可以亲自证实这一点。我在编写IO基准应用程序时亲眼目睹了效果。)
    • 你的解决方案初始化为零,请看here
    【解决方案2】:

    查看memory mapped files

    它们非常符合您描述的用例、高性能和随机访问。

    我相信它们不需要创建为大文件。您只需在它们上设置一个较大的最大尺寸,当您写入以前未触及的部分时,它们将被扩展。

    【讨论】:

    • 使用内存映射文件还引入了更多复杂性:错误是通过结构化异常而不是函数返回值报告的,并且您将无法在 32 位 Windows 上将整个 8 GB 文件映射到内存中因为您只有 2 GB 的虚拟地址空间(如果幸运的话,还有 3 GB)。
    • 您肯定需要使用一个(或多个,如果您独立使用文件的许多部分)窗口来将相关内容映射到内存中。无论如何,如果使用标准文件 IO,您就无法访问整个文件。它只是使用 fseeks 完成,而不是更改映射到内存的内容。
    【解决方案3】:

    好吧this解决方案还不错,但你要找的是SetFileValidData

    正如 MSDN 所说:

    SetFileValidData 函数允许您避免使用 非顺序写入文件时为零。

    所以这总是让磁盘数据保持原样,SetFilePointerEx 应该将所有数据设置为零,所以大分配需要一些时间。

    【讨论】:

    • 请注意,SetFileValidData 是一个巨大的安全风险,这就是为什么您也需要一个特权进程才能使用此功能。如果您有足够的地址空间,Laserallan(内存映射文件)提出的解决方案是更可取的。创建任意大小的映射既快速安全。
    【解决方案4】:

    使用“fsutil”命令:

    E:\VirtualMachines>fsutil 文件创建新 用法:fsutil 文件 createnew 例如:fsutil 文件 createnew C:\testfile.txt 1000

    阅读

    附:适用于 Windows:2000/XP/7

    【讨论】:

      【解决方案5】:

      如果您使用的是 NTFS,那么sparse files 是最好的选择:

      包含大量数据的文件 zeros 被称为包含稀疏数据 放。像这样的文件通常是 非常大——例如,一个文件 包含要处理的图像数据 或高速内的矩阵 数据库。文件的问题 包含稀疏数据集的是 大部分文件没有 包含有用的数据,并且由于 这是一种低效的使用 磁盘空间。

      NTFS 文件中的文件压缩 系统是部分解决方案 问题。文件中的所有数据 没有明确写的就是明确的 设置为零。文件压缩压缩包 这些零范围。然而,一个 文件压缩的​​缺点是 访问时间可能会因数据而增加 压缩和解压。

      引入了对稀疏文件的支持 在 NTFS 文件系统中作为另一种方式 使磁盘空间使用更多 高效的。稀疏文件时 功能启用,系统 不分配硬盘空间给 一个文件,除了它所在的区域 包含非零数据。当一个写 操作试图在大 缓冲区中的数据量为 零,零不写入 文件。相反,文件系统 创建一个内部列表,其中包含 零点的位置 文件,并查阅此列表 在所有读取操作期间。当一个 读操作在区域中执行 零所在的文件, 文件系统返回 适当数量的零 为读取分配的缓冲区 手术。这样,维护 稀疏文件对所有人都是透明的 访问它的进程,并且更多 比压缩更有效 特定场景。

      【讨论】:

      • 不 - 他需要预先分配范围。
      【解决方案6】:

      我知道您的问题被标记为 Windows,如果您确定不必将应用程序移植到其他平台,Brian R. Bondy 为您的问题提供了最佳答案。但是,如果您可能必须将您的应用程序移植到其他平台,您可能想要做一些更像 Adrian Cornish 提出的作为“如何创建“x”大小的文件?”问题的答案的事情。在How to create file of "x" size?找到。

      FILE *fp=fopen("myfile", "w");
      fseek(fp, 1024*1024, SEEK_SET);
      fputc('\n', fp);
      fclose(fp);
      

      当然,还有一个额外的转折。 Adrian Cornish 提出的答案使用了具有以下签名的 fseek 函数。

      int fseek ( FILE * stream, long int offset, int origin );
      

      问题是您想要创建一个文件大小超出 32 位整数范围的非常大的文件。您需要使用 fseek 的 64 位等效项。不幸的是,在不同的平台上它有不同的名称。

      位于http://mosaik-aligner.googlecode.com/svn-history/r2/trunk/src/CommonSource/Utilities/LargeFileSupport.h 的头文件 LargeFileSupport.h 提供了解决此问题的方法。

      这将允许您编写以下函数。

      #include "LargeFileSupport.h"
      /* Include other headers. */
      
      bool createLargeFile(const char * filename, off_type size)
      {
          FILE *fp = fopen(filename, "w");
          if (!fp)
          {
              return false;
          }
          fseek64(fp, size, SEEK_SET);
          fputc('\n', fp);
          fclose(fp);
      }
      

      我想我会添加这个,以防这些信息对你有用。

      【讨论】:

        猜你喜欢
        • 2010-11-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-02-06
        • 2011-07-26
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多