《Windows via C/C++》學習筆記 —— 裝置I/O之“檔案裝置”

來源:互聯網
上載者:User

  本來不打算寫這篇的,但是檔案的重要性大家都知道。在裝置I/O中,有一種裝置叫檔案裝置,這是一個抽象的概念,就把它理解為檔案就行了。

  檔案裝置,可以通過CreateFile函數開啟,得到一個檔案物件控點。

 

  在檔案中,有兩個比較重要的屬性:

1、檔案大小:在32位中最大為4GB,64位中可以達到16EB。

2、檔案讀寫指標:這個指標表明讀寫位置,大小範圍可以超出檔案的大小。

 

  先討論檔案的大小。

  要得到檔案的大小,可以使用GetFileSizeEx函數:

BOOL GetFileSizeEx(
   HANDLE         hFile,     //檔案物件控點
   PLARGE_INTEGER pliFileSize);  //LARGE_INTEGER聯合的指標,返回大小

 

  這個函數接受一個LARGE_INTEGER聯合的指標,用來返迴文件大小,這個結構可以表示64位值:

typedef union _LARGE_INTEGER {
   struct {
      DWORD LowPart;    // 低32位值
      LONG HighPart;       // 高32位值

   };
   LONGLONG QuadPart;   // 64位值得
} LARGE_INTEGER, *PLARGE_INTEGER;

 

  從這個定義可以看出,該聯合可以用QuadPart表示一個64位值,也可以差分成兩個32位值。這個聯合有一個無符號數版本,叫做ULAGER_INTEGER聯合,對應的3個成員都是儲存的無符號數。

 

  還有一個函數可以得到一個檔案的大小:

DWORD GetCompressedFileSize(
   PCTSTR pszFileName,          //檔案路徑名
   PDWORD pdwFileSizeHigh); //檔案大小如果大於4GB,高32位值由該參數返回

 

  這個函數接受一個檔案的路徑名稱,返迴文件大小的低32位值,高32位值由參數pdwFileSizeHigh返回。與GetFileSizeEx不同的是,該函數返回一個檔案的物理大小,而GetFileSizeEx返迴文件的邏輯大小。

  比如一個檔案大小為100KB,它被壓縮為85KB,如果使用GetFileSizeEx,則返回100KB,使用GetCompressedFileSize則返回85KB。

  與GetFileSizeEx不同的是,該函數接受一個字串,指明檔案路徑,這就可以直接查詢某個檔案大小,而不要先開啟它獲得它的控制代碼。

  可以如下使用該函數:

ULARGE_INTEGER ulFileSize;     //與LARGE_INTEGER聯合類似,儲存無符號數
ulFileSize.LowPart = GetCompressedFileSize(TEXT("SomeFile.dat"),
   &ulFileSize.HighPart);     //取得目前的目錄下的SomeFile.dat檔案大小

  這樣,64位的檔案大小儲存在ulFileSize.QuadPart中。

 

  討論完了檔案的大小,下面來討論檔案讀寫指標。

  CreateFile函數建立或開啟了一個檔案核心對象,該核心對象中管理著一個“檔案讀寫指標”。該指標指明了一個64位的位移量。初始情況下,該指標設定為0,即你讀取或寫入資料的時候從檔案開始處進行,即從位移量為0的地方開始。每次讀取或寫入N位元組的資料,系統更新該讀寫指標,使位移量加上N個位元組。比如下面代碼反映了讀取檔案前100個位元組的資料:

BYTE pbFirst[50], pbSecond[50];
DWORD dwNumBytes;
HANDLE hFile = CreateFile(TEXT("MyFile.dat"), ...); //指標初始化為0
ReadFile(hFile, pbFirst, 50, &dwNumBytes, NULL);    //讀取第0~49位元組
ReadFile(hFile, pbSecond, 50, &dwNumBytes, NULL);//讀取第50~99位元組

 

  需要注意的是,一個檔案物件控點對應一個讀寫指標,如果一個檔案被開啟多次,那麼就有多個檔案對象,每個檔案對象管理著一個讀寫指標,這些指標相互之間不影響。比如下面的代碼:

BYTE pb[10];
DWORD dwNumBytes;
HANDLE hFile1 = CreateFile(TEXT("MyFile.dat"), ...); //指標初始化為0
HANDLE hFile2 = CreateFile(TEXT("MyFile.dat"), ...); //指標初始化為0
ReadFile(hFile1, pb, 10, &dwNumBytes, NULL);  //讀取第0~9位元組
ReadFile(hFile2, pb, 10, &dwNumBytes, NULL);  //也是讀取第0~9位元組

 

  上面這段代碼,hFile1和hFile2是同一個檔案的兩個不同的檔案核心對象的控制代碼,這兩個核心對象管理著兩個不同檔案指標,所以改變其中一個的讀寫指標,不會影響另一個。

  下面這段代碼更能說明問題:

BYTE pb[10];
DWORD dwNumBytes;
HANDLE hFile1 = CreateFile(TEXT("MyFile.dat"), ...); //讀寫指標初始化為0
HANDLE hFile2;     //另一個檔案控制代碼

//將本進程內hFile1控制代碼值複製給本進程中的hFile2
DuplicateHandle(
   GetCurrentProcess(), hFile1,
   GetCurrentProcess(), &hFile2,
   0, FALSE, DUPLICATE_SAME_ACCESS);
ReadFile(hFile1, pb, 10, &dwNumBytes, NULL);   //讀取第0~9位元組
ReadFile(hFile2, pb, 10, &dwNumBytes, NULL);   //讀取第10~19位元組

 

  上面這段代碼,使用DuplicateHandle函數複製控制代碼,使得兩個控制代碼hFile1和hFile2共用同一個檔案核心對象,因此讀寫指標也是共用的。

 

  可以使用SetFilePointerEx函數來定位檔案讀寫指標:

BOOL SetFilePointerEx(
   HANDLE         hFile,     //檔案核心物件控點
   LARGE_INTEGER  liDistanceToMove,     //64位元,移動位元組數
   PLARGE_INTEGER pliNewFilePointer,    //返回新的檔案讀寫指標位置
   DWORD          dwMoveMethod);        //移動方式

  該函數中dwMoveMethod告訴系統如何移動。FILE_BEGIN,表示從檔案頭開始移動;FILE_END,表示從檔案尾往前移動;FILE_CURRENT,表示從當前讀寫指標位置移動。移動的位移量在第2個參數liDistaceToMove中。

 

  有幾點需要注意

  • 將檔案讀寫指標的位置設定為超過檔案大小範圍是合法的。這麼做不會使得檔案大小變大,除非調用函數SetEndOfFile。
  • 當開啟檔案使用函數CreateFile時,該函數的dwFlagsAndAttributes參數中包括FILE_FLAG_NO_BUFFERING,檔案讀寫指標只能被設定為硬碟扇區的單位大小。
  • 沒有GetFilePointerEx函數來取得當前檔案指標位置,可以調用SetFilePointerEx函數來得到其位置,要把第二個參數設定為0,如下代碼:
LARGE_INTEGER liCurrentPosition = { 0 };
SetFilePointerEx(hFile, liCurrentPosition,
                        &liCurrentPosition,FILE_CURRENT);

 

  當檔案被關閉的時候,系統會在檔案上設定一個結束位置,以確定該檔案的大小。當然,你也可以自己設定檔案的結束位置,以此來改變檔案的大小。使用SetEndOfFile函數:

BOOL SetEndOfFile(HANDLE hFile);

 

  該檔案在當前的檔案讀寫指標處設定檔案的結束標誌,來截斷或擴充檔案的大小。比如,你想設定一個檔案的大小為1024位元組的話,可以通過以下代碼實現:

HANDLE hFile = CreateFile(...);
LARGE_INTEGER liDistanceToMove;
liDistanceToMove.QuadPart = 1024;
//設定檔案指標
SetFilePointerEx(hFile, liDistanceToMove, NULL, FILE_BEGIN);
SetEndOfFile(hFile);     //在檔案指標處設定結束標誌
CloseHandle(hFile);

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.