在UNIX/LINUX系统中,文件位移量可以大于文件的当前长度,这种情况下向文件中写入数据就会产生文件空洞(hole),这些没写入数据的文件空洞部分默认会被0填满。虽然这些文件空洞并没有实际的数据,但是它们仍然占据硬盘空间。
在Windows下同样支持这种文件空洞,以下简单的代码产生一个6KB的空洞文件:
#include <afx.h> #include <iostream> using namespace std; int _tmain(int argc, _TCHAR* argv[]) { CFile testFile(_T("D:\test"), CFile::modeCreate | CFile::modeWrite); CHAR buff[1024]; memset(buff, 12, 1024); testFile.Write(buff, 1024); testFile.Seek(1024 * 3, CFile::begin); memset(buff, 22, 1024); testFile.Write(buff, 1024); testFile.Seek(1024 * 5, CFile::begin); memset(buff, 20, 1024); testFile.Write(buff, 1024); testFile.Close(); return 0; }
用Sublime Text2打开,可以发现中间两部分是NULL(0),这就是文件空洞
从代码地图上可以看到此文件有3KB是空的:
Windows下的NTFS文件系统还支持文件空洞的压缩,那些0都是无用的数据,却又占据了空间资源,NTFS文件空洞的压缩算法可以释放这些0字节的空间。这种文件被称为稀疏文件,通过指定DeviceIoControl函数
BOOL WINAPI DeviceIoControl(
_In_ HANDLE hDevice,
_In_ DWORD dwIoControlCode,
_In_opt_ LPVOID lpInBuffer,
_In_ DWORD nInBufferSize,
_Out_opt_ LPVOID lpOutBuffer,
_In_ DWORD nOutBufferSize,
_Out_opt_ LPDWORD lpBytesReturned,
_Inout_opt_ LPOVERLAPPED lpOverlapped
);
设置FSCTL_SET_SPARSE标记可以产生稀疏文件,以下代码是一个例子:
hFile = CreateFile("tmp_file", GENERIC_WRITE|GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,NULL, CREATE_ALWAYS,0,NULL); DWORD dwTemp; DeviceIoControl(hFile,FSCTL_SET_SPARSE, NULL,0,NULL,0,&dwTemp,NULL); SetFilePointer(hFile, 0x100000, NULL, FILE_BEGIN); WriteFile(hFile,"123", 3, &nWritten, NULL); SetEndOfFile(hFile); CloseHandle(hFile);
通过GetFileInformationByHandle可以查看文件是否为稀疏文件:
BOOL WINAPI GetFileInformationByHandle(
_In_ HANDLE hFile,
_Out_ LPBY_HANDLE_FILE_INFORMATION lpFileInformation
);
FSCTL_SET_SPARSE