【发布时间】:2010-10-02 02:27:03
【问题描述】:
我需要创建相对较大 (1-8 GB) 的文件。在 Windows 上使用 C 或 C++ 最快的方法是什么?我需要即时创建它们,速度确实是个问题。文件将用于存储仿真,即以不同的偏移量随机访问,我需要所有存储都将预先分配但未初始化,目前我们正在使用虚拟数据写入所有存储,并且花费的时间太长。
谢谢。
【问题讨论】:
我需要创建相对较大 (1-8 GB) 的文件。在 Windows 上使用 C 或 C++ 最快的方法是什么?我需要即时创建它们,速度确实是个问题。文件将用于存储仿真,即以不同的偏移量随机访问,我需要所有存储都将预先分配但未初始化,目前我们正在使用虚拟数据写入所有存储,并且花费的时间太长。
谢谢。
【问题讨论】:
使用 Win32 API,CreateFile、SetFilePointerEx、SetEndOfFile 和 CloseHandle。以同样的顺序。
诀窍在于 SetFilePointerEx 函数。来自 MSDN:
注意,设置不是错误 指向超出位置的文件指针 文件的结尾。的大小 文件不会增加,直到您调用 SetEndOfFile、WriteFile 或 WriteFileEx 函数。
在将文件从一个位置复制到另一个位置时,Windows 资源管理器实际上会做同样的事情。这样做是为了使磁盘不需要为碎片磁盘重新分配文件。
【讨论】:
SetEndOfFile() 在写入文件时会导致严重的延迟。如果您写入文件的中间,Windows 会将所有尚未写入的块清零,直到写入的位置。见blogs.msdn.com/b/oldnewthing/archive/2011/09/22/10215053.aspx(我可以亲自证实这一点。我在编写IO基准应用程序时亲眼目睹了效果。)
它们非常符合您描述的用例、高性能和随机访问。
我相信它们不需要创建为大文件。您只需在它们上设置一个较大的最大尺寸,当您写入以前未触及的部分时,它们将被扩展。
【讨论】:
好吧this解决方案还不错,但你要找的是SetFileValidData
正如 MSDN 所说:
SetFileValidData 函数允许您避免使用 非顺序写入文件时为零。
所以这总是让磁盘数据保持原样,SetFilePointerEx 应该将所有数据设置为零,所以大分配需要一些时间。
【讨论】:
SetFileValidData 是一个巨大的安全风险,这就是为什么您也需要一个特权进程才能使用此功能。如果您有足够的地址空间,Laserallan(内存映射文件)提出的解决方案是更可取的。创建任意大小的映射既快速又安全。
使用“fsutil”命令:
E:\VirtualMachines>fsutil 文件创建新 用法:fsutil 文件 createnew 例如:fsutil 文件 createnew C:\testfile.txt 1000
阅读
附:适用于 Windows:2000/XP/7
【讨论】:
如果您使用的是 NTFS,那么sparse files 是最好的选择:
包含大量数据的文件 zeros 被称为包含稀疏数据 放。像这样的文件通常是 非常大——例如,一个文件 包含要处理的图像数据 或高速内的矩阵 数据库。文件的问题 包含稀疏数据集的是 大部分文件没有 包含有用的数据,并且由于 这是一种低效的使用 磁盘空间。
NTFS 文件中的文件压缩 系统是部分解决方案 问题。文件中的所有数据 没有明确写的就是明确的 设置为零。文件压缩压缩包 这些零范围。然而,一个 文件压缩的缺点是 访问时间可能会因数据而增加 压缩和解压。
引入了对稀疏文件的支持 在 NTFS 文件系统中作为另一种方式 使磁盘空间使用更多 高效的。稀疏文件时 功能启用,系统 不分配硬盘空间给 一个文件,除了它所在的区域 包含非零数据。当一个写 操作试图在大 缓冲区中的数据量为 零,零不写入 文件。相反,文件系统 创建一个内部列表,其中包含 零点的位置 文件,并查阅此列表 在所有读取操作期间。当一个 读操作在区域中执行 零所在的文件, 文件系统返回 适当数量的零 为读取分配的缓冲区 手术。这样,维护 稀疏文件对所有人都是透明的 访问它的进程,并且更多 比压缩更有效 特定场景。
【讨论】:
我知道您的问题被标记为 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);
}
我想我会添加这个,以防这些信息对你有用。
【讨论】: