如何在 Windows 上的 C/C++ 中为文件预分配空间?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7970333/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 18:22:58  来源:igfitidea点击:

How do you pre-allocate space for a file in C/C++ on Windows?

c++cwindowsfile

提问by user1024191

I'm adding some functionality to an existing code base that uses pure C functions (fopen, fwrite, fclose) to write data out to a file. Unfortunately I can't change the actual mechanism of file i/o, but I have to pre-allocate space for the file to avoid fragmentation (which is killing our performance during reads). Is there a better way to do this than to actually write zeros or random data to the file? I know the ultimate size of the file when I'm opening it.

我正在向使用纯 C 函数(fopen, fwrite, fclose)将数据写入文件的现有代码库添加一些功能。不幸的是,我无法更改文件 i/o 的实际机制,但我必须为文件预先分配空间以避免碎片化(这会在读取过程中扼杀我们的性能)。有没有比实际将零或随机数据写入文件更好的方法呢?当我打开文件时,我知道文件的最终大小。

I know I can use fallocate on linux, but I don't know what the windows equivalent is.

我知道我可以在 linux 上使用 fallocate,但我不知道 windows 等价物是什么。

Thanks!

谢谢!

回答by Michael Goldshteyn

Programatically, on Windows you have to use Win32 API functions to do this:

以编程方式,在 Windows 上,您必须使用 Win32 API 函数来执行此操作:

SetFilePointerEx() followed by SetEndOfFile()

You can use these functions to pre-allocate the clusters for the file and avoid fragmentation. This works much more efficiently than pre-writing data to the file. Do this prior to doing your fopen().

您可以使用这些函数为文件预先分配集群并避免碎片化。这比将数据预写入文件更有效。在执行您的fopen().

If you want to avoid the Win32 API altogether, you can also do it non-programatically using the system() function to issue the following command:

如果您想完全避免 Win32 API,您也可以使用 system() 函数以非编程方式发出以下命令:

fsutil file createnew filename filesize

回答by Adam Rosenfield

You can use the SetFileValidDatafunction to extend the logical length of a file without having to write out all that data to disk. However, because it can allow to read disk data to which you may not otherwise have been privileged, it requires the SE_MANAGE_VOLUME_NAMEprivilege to use. Carefully read the Remarkssection of the documentation.

您可以使用该SetFileValidData函数来扩展文件的逻辑长度,而无需将所有数据写入磁盘。但是,因为它可以允许读取您可能没有特权的磁盘数据,所以它需要SE_MANAGE_VOLUME_NAME特权才能使用。仔细阅读文档的备注部分。

I'd recommend instead just writing out the 0's. You can also use SetFilePointerExand SetEndOfFileto extend the file, but doing so still requires writing out zeros to disk (unless the file is sparse, but that defeats the point of reserving disk space). See Why does my single-byte write take forever?for more info on that.

我建议改为只写出 0。您还可以使用SetFilePointerExSetEndOfFile扩展文件,但这样做仍然需要将零写入磁盘(除非文件稀疏,但这与保留磁盘空间的意义相去甚远)。请参阅为什么我的单字节写入需要永远?有关更多信息。

回答by Martin Beckett

Sample code, note that it isn't necessarily faster especially with smart filesystems like NTFS.

示例代码,请注意它不一定更快,尤其是对于像 NTFS 这样的智能文件系统。

if (  INVALID_HANDLE_VALUE != (handle=CreateFile(fileName,GENERIC_WRITE,0,0,CREATE_ALWAYS,FILE_FLAG_SEQUENTIAL_SCAN,NULL) )) {                                               
        // preallocate 2Gb disk file                
        LARGE_INTEGER size;
        size.QuadPart=2048 * 0x10000;
        ::SetFilePointerEx(handle,size,0,FILE_BEGIN);
        ::SetEndOfFile(handle);
        ::SetFilePointer(handle,0,0,FILE_BEGIN);
}

回答by Ferruccio

You could use the _chsize()function.

您可以使用_chsize()函数。

回答by Jim Fell

Check out this example on Code Project. It looks pretty straightforward to set the file size when the file is initially crated.

在 Code Project 上查看此示例。在最初创建文件时设置文件大小看起来非常简单。

http://www.codeproject.com/Questions/172979/How-to-create-a-fixed-size-file.aspx

http://www.codeproject.com/Questions/172979/How-to-create-a-fixed-size-file.aspx

FILE *fp = fopen("C:\myimage.jpg","ab");

fseek(fp,0,SEEK_END);
long size = ftell(fp);

char *buffer = (char*)calloc(500*1024-size,1);
fwrite(buffer,500*1024-size,1,fp);

fclose(fp);