在磁盘上给文件快速预留一大片空间

来源:互联网 发布:windows phone 8手机 编辑:程序博客网 时间:2024/06/04 18:46

在有多个线程操作一个磁盘的时候,在创建文件的时候需要先把文件撑大,把空间占住,后续在向文件写入。

windows下:

方法1:SetEndOfFile

方法2:seek到文件大小的位置,然后写入一个0。

linux下:

如果是ext3用:posix_fallocate

如果是ext4用:fallocate




比如迅雷下载,下载开始之前会在磁盘上创建一个与下载文件同样大小的空白的原始文件,然后下载过程中去改写这个文件。如果在生成这个空白的原始文件时,反复调用的WriteFile来写入文件。当文件较大时,无法保证在写这个文件的过程中,系统中有其他进程也向磁盘申请空间,这样还是会造成磁盘碎片问题,该文件的不连续会造成日后对该文件读取的速度降低,但通常不考虑碎片问题。

我实际编程测了一下:
使用CreateFile/SetFilePointer/SetEndOfFile,速度很快,支持大于4GB的文件;
使用CreateFileMapping,速度也很快,但是32位程序下只能是小于2GB的文件,而且占用地址空间了,不过后续的“改写”操作,将更加容易进行了;
使用WriteFile,速度相当慢;
fseek的底层应该跟SetFilePointer是一样的。

最后,我是这样分析的:
使用SetFilePointer和CreateFileMapping,都相当于用户向文件系统申请一大块“逻辑上连续”的磁盘空间,因为该申请的速度很快,所以降低了其他进程与此同时申请的几率,从而降低了碎片程度,但是“物理位置”还是由文件系统决定的,只能说文件系统看到用户申请连续空间后,尽量去满足用户的请求以达到优化的目的,但是不一定最终给出真正物理连续的空间。
以上2种方法,都没有实际往磁盘中写数据,只是记录下簿记信息,因此速度巨快。但是用了WriteFile,就要慢慢的写入磁盘了。

核心代码:

HANDLE hOpenFile =NULL;     hOpenFile = (HANDLE)CreateFile("D:\\a.txt", GENERIC_READ |GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, NULL, NULL);     longret;     longlow = 1;     longhigh = 2;     ret = SetFilePointer (hOpenFile, low, &high, FILE_BEGIN);     if(ret ==HFILE_ERROR)     {         MessageBox ("error");     }     SetEndOfFile(hOpenFile);     CloseHandle(hOpenFile);

 

关于这几个API函数的详细说明可以参照MSDN或百度百科。

其中在SetFilePointer中low代表文件大小的低32位,high代表高32位,所以最大可创建2^64大小的文件。

 

也可以试着使用:

CFile file;     file.Open("F:\\result.txt", CFile::modeReadWrite);     file.SetLength (0x7fffffff);     file.Close ();

但是只能创建最大2^32的文件



NTFS的试过可以,但FAT32的速度很慢