All about sparse file in WINDOWS(關於WINDOWS稀疏文件)


      稀疏文件(Sparse File), 指的是文件中出現大量的0數據,這些數據對我們用處不大,但是卻一樣的佔用我們的空間,針對此,WINNT 3.51中的NTFS文件系統對此進行了優化,那些無用的0字節被用一定的算法壓縮起來,使得這些0字節不再佔用那麼多的空間,在你聲明一個很大的稀疏文件時(例如 100GB),這個文件實際上並不需要佔用這麼大的空間,因爲裏面大都是無用的0數據,那麼,NTFS對稀疏文件的壓縮算法可以釋放這些無用的0字節空間, 可以說這是對磁盤佔用空間以及效率的一種優化,記住,FAT32上並不支持稀疏文件的壓縮(至少我在自己機子上測試得出如此結論)。


      這裏,我們將粗略的介紹:

1,如何判斷一個磁盤是否支持稀疏文件。
2,如何判斷一個文件是否是稀疏文件。
3,如何產生一個稀疏文件。
4,假如系統支持稀疏文件,如何聲明這個文件是稀疏文件。

     因爲這是我工作中出現的問題,所以可能不會深究裏面的算法和操作系統機制,但是文章末尾會附上參考資料。
 若有問題,可以聯繫我 [email protected](工作郵箱)  或者 [email protected](私人郵箱) 

1.1   判斷一個磁盤是否是稀疏文件。

我們可以通過一個系統函數GetVolumeInformation 來判斷某個磁盤是否支持稀疏文件的壓縮。MSDN中的函數原型如下:

GetVolumeInformation

 

The GetVolumeInformation function retrieves information about a file system and volume that have a specified root directory.

 

BOOL GetVolumeInformation(
LPCTSTR lpRootPathName,
  LPTSTR lpVolumeNameBuffer,
  DWORD nVolumeNameSize,
  LPDWORD lpVolumeSerialNumber,
  LPDWORD lpMaximumComponentLength,
  LPDWORD lpFileSystemFlags,
  LPTSTR lpFileSystemNameBuffer,
  DWORD nFileSystemNameSize
);
我們只要把查詢到的Flag 跟 FILE_SUPPORTS_SPARSE_FILES 位與(&),便可以知道該磁盤是否支持。





這是從我的工具集(toolset)裏摘錄的例子代碼:
    CHAR szVolName[MAX_PATH], szFsName[MAX_PATH];
    DWORD dwSN, dwFSFlag, dwMaxLen, nWritten;
    BOOL bSuccess;
    HANDLE hFile;
    bSuccess 
= GetVolumeInformation(NULL,
        szVolName,
        MAX_PATH,
        
&dwSN, 
        
&dwMaxLen, 
        
&dwFSFlag, 
        szFsName,
        MAX_PATH);

    
if (!bSuccess) {
        printf(
"errno:%d", GetLastError());
        return 
-1;
    }
    printf(
"vol name:%s /t fs name:%s sn: %d./n", szVolName, szFsName, dwSN);
    
if (dwFSFlag&FILE_SUPPORTS_SPARSE_FILES) {
        printf(
"support sparse file./n");
    }
else{
        printf(
"no support sparse file./n");
    }

2.1 如何判斷一個文件是否是稀疏文件。



我們可以通過 GetFileInformationByHandle()函數來判斷一個文件是否是稀疏文件。這是MSDN裏面的定義。

 

The GetFileInformationByHandle function retrieves file information for the specified file.

 

BOOL GetFileInformationByHandle(
HANDLE hFile,
  LPBY_HANDLE_FILE_INFORMATION lpFileInformation
);
 
例子代碼如下:
 
HANDLE hFile;
BY_HANDLE_FILE_INFORMATION stFileInfo;

//Open/create file to get the file handle
hFile 
= CreateFile();
//Get the file information
GetFileInformationByHandle(hFile, 
&stFileInfo);

if(stFileInfo.dwFileAttributes & FILE_ATTRIBUTE_SPARSE_FILE)
{
    
//Sparse file
}
else{
   
//Not sparse file
}
 
3.1, 如何產生一個稀疏文件並聲明該文件是稀疏文件。
   大部分文件,在你改變它的EndOfFile的時候,中間的空白會被操作系統填0,也就是說,如果你用SetFilePointer() 和SetEndOfFile()來
產生一個很大的文件,那麼這個文件它佔用的是真正的磁盤空間,即使裏面全是0,因爲系統默認的會在DeviceIoControl()中的ControlCode裏用
FSCTL_SET_ZERO_DATA標記,這個標記使得那些文件空洞被0所填充。爲了節省磁盤空間,我們必須把一個文件聲明爲稀疏文件,以便讓系統
把那些無用的0字節壓縮,並釋放相應的磁盤空間,方法如下:
 
    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);
注意到FSCTL_SET_SPARSE這個標記了嗎?正是這個標記,告訴系統該文件是稀疏文件,如果該文件所在的磁盤支持稀疏
文件的壓縮,則系統會釋放不必要的0字節空間。你可以用這個方法創建一個100GB得文件試一下(示例裏是1M),記得右鍵看看文件屬性
裏的‘大小’和佔用空間,它被聲明爲100GB,但是實際上那些0字節基本不佔用空間,而你寫入的“123”是佔用實際的
磁盤空間的。
   注意:在FAT32得磁盤裏,因爲沒有對SPARSE FILE得支持,所以您創建的空洞文件全部被填零,即使你聲明它是一個稀疏
文件,也沒有任何作用,您聲明這個文件多大,它就佔用多大的空間。
   另外,如果您編譯 DeviceIoControl這個函數出現 "'FSCTL_SET_SPARSE' : undeclared identifier"之類的情況
請這樣做:
#include <windows.h>
#define   _WIN32_WINNT         0x0501
#include <Winioctl.h>
 
以上資料參閱了:http://www.flexhex.com/docs/articles/sparse-files.phtml
發佈了80 篇原創文章 · 獲贊 8 · 訪問量 34萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章