在Windows系統中,創建和打開文件都是使用API函數CreateFile,CreateFile通過指定不同的參數來表示是新建一個文件,打開已經存在的文件,還是重新建立文件等。讀寫文件最為直接的方式是使用ReadFile和WriteFile函數,也可以使用文件鏡像,獲取文件大小一般使用GetFileSize函數,也可以使用GetFileAttributesEx等函數(在上節介紹)。讀寫文件、獲取文件大小之前都需要使用CreateFile創建或打開的文件,獲得文件句柄。
在文件操作中,文件句柄是一個關鍵的概念。文件句柄惟一標識了一個文件,ReadFile、WriteFile、GetFileSize等函數是使用文件句柄作為參數來表示,用戶需要讀、寫、獲取大小的文件是哪一個文件。在對文件進行操作前,都必須要使用CreateFile獲得文件句柄。
(1)CreateFile
CreateFile是文件操作中最主要的一個函數。幾乎所有的文件操作都需要使用到文件句柄。而CreateFile函數為這些操作建立文件句柄。CreateFile函數的參數多,而且比較復雜,涉及文件名、文件的共享模式、存取方式、操作模式、權限、標志和文件屬性等。每一個參數都可以有多種值可供選擇,代表了不同的意義。
◇參數
lpFileName:輸入參數,操作對象文件的相對路徑或絕對路徑。
dwDesiredAccess:輸入參數,指明對文件對象的操作存取方式,可以是GENERIC_READ,表示需要讀文件;可以是GENERIC_WRITE,表示需要寫文件;也可以是GENERIC_READGENERIC_WRITE,表示既可以讀也可以寫。
dwShareMode:輸入參數,共享模式。指明與其他進程是否共享該文件,可以是共享讀(FILE_SHARE DELETE)、共享寫(FILE_SHARE_WRITE)、共享刪除(FILE_SHARE.READ),如果要指明多個屬性,使用“位與~‘I”運算。如果指明上述參數,其他進程就可以對文件進行相關操作。如果本進程需要獨占本文件,則將本參數設置為0。
lpSecurityAttributes:指向SECURITY_ATTRIBUTES結構的指針,表示本文件句柄的安全屬性,能影響其是否可被子進程繼承等操作。如果設定為NULL,則子進程不可繼承本句柄。SECURITY ATTRIBUTES結構不常用,對此數據結構的設置,涉及Windows系統中對權限管理的原理,在本章中不作詳細說明。
dwCreationDisposition:輸入參數,操作模式。
dwFlagsAndAttributes:輸入參數,文件屬性和文件標志
一般情況下文件屬性較常用,而操作標志不常用,可以使用“1”運算符指定多個屬性和標志。
hTemplateFile:輸入參數,當存取權限包括GENERIC_WRITE時,可以設置為一個模板文件的句柄。一般情況下,可設置為NULL,表示不使用模板文件。
◇返回值
返回HANDLE數據類型值,表示文件的句柄,如果返回INVALID_HANDLE_VALUE,表示操作失敗。
(2)ReadFile。
ReadFile動能是從文件中讀出數據。需要使用CreateFile所返回的文件句柄。
◇參數
hFile:輸入參數,讀取數據的文件對象,由CreateFile創建,調用CreateFile打開文件時需要指明GENERIC_READ讀取操作模式。
lpBuffer:輸入參數,指向讀取文件數據存儲的內存緩沖區。
nNumberOfBytesToRead:輸入參數,指明需要從文件中讀出的數據的大小,不能大於lpBuffer內存塊的大小,否則會造成溢出。
lpNumberOfBytesRead:輸出參數,指向存儲實際讀出的數據大小的DWORD變量。在讀文件時,可能由於已經到達文件尾等原因,其值可能小於rtNumberOfBytesToRead。如果lpOverlapped為NULL,則該參數不能為NULL。
lpOverlapped:輸入參數,指向OVERLAPPED結構體的指針,如果調用CreateFile時設置了FILE_FLAG_OVERLAPPED標志,則需要使用該參數,否則可以為NULL。
◇返回值
返回BOOL值,表示讀文件是否成功。
◇使用說明
在讀的過程中,文件指針會隨着讀操作的進行而自動移動,在循環調用本函數時,會順序讀出文件的內容,如果程序返回失敗,可以使用GetLastError函數獲取錯誤信息。
(3)WriteFile。
WriteFile函數的功能是將數據寫入到文件中,寫入到文件指針所在的位置,寫入操作完成后,文件指針會移動到寫入的數據之后
◇參數
hFile:輸入參數,寫入數據的文件對象,由CreateFile創建,調用CreateFile打開文件時,需要指明GENERIC_WRITE讀取操作模式。
lpBuffer:輸入參數,指向需寫入文件數據存儲的內存緩沖區。
nNumberOBytesToWrite:輸入參數,指明需要寫入文件中的數據的大小。
lpNumberOiBytesWritten:輸出參數,指向存儲真實寫入的數據大小的變量,可能由於已經到達文件尾等原因,其值可能與nNumberOfBytesToWrite不同。如果lpOverlapped為NULL,則該參數不能為NULL。
lpOverlapped:輸入參數,指向OVERLAPPED結構體的指針,如果調用CreateFile時設置了FILE_FLAG_OVERIAPPED標志,則需要使用該參數。可以為NULL。
◇返回值
返回BOOL值,表示寫文件是否成功。
◇使用說明
在讀的過程中,文件指針會隨着寫操作的進行而移動,在循環調用本函數時,會按順序寫入文件內容。如果程序返回失敗,可以使用 GetLastError函數獲取錯誤信息。
(4)GetFileSize、GetFileSizeEX.
GetFileSize、GetFileSizeEX的功能是一致的,都是獲取文件大小
◇參數
GetFileSize的參數如下。
hFile:輸入參數,讀取數據的文件對象,由CreateFile創建,調用CreateFile打開文件時需要指明GENERIC_READ讀取操作模式或者GENERIC_WRITE寫入操作模式。
lpFileSizeHigh:輸出參數,表示得到的文件大小的高32位。該參數可以為NULL,為NULL時表示文件大小可以用DWORD表示。具體解釋請參考返回值部分。
GetFileSizeEx的參數如下。
hFile:輸入參數,讀取數據的文件對象,由CreateFile創建,調用CreateFile打開文件時,需要指明GENERIC_READ讀取操作模式或者GENERIC_WRITE寫入操作模式。
lpFileSize:輸出參數,指向儲存文件大小的一個LARGE_ INTEGER聯合體,前面已經介紹過了LARGE.1NTEGER結構的相關內容,參見API 9 小節關鍵數據結構部分。
◇返回值
GetFileSize成功時,返回值為一個表示文件大小DWORD值。
GetFileSize失敗時,如果lpFileSizeHigh為NULL,返回INVALID_ FILE_SIZE並可以調用GetLastError函數獲取更詳細的錯誤信息;如果lpFileSizeHigh為非NULL,那么同樣返回INVALID_FILE_SIZE並且嘗試讀取lpFileSizeHigh指向的值放在高32位,並將其和返回的低32位DWORD連起來成為一個64位的值來表示文件大小。lpFileSizeHigh為合法值則GetLastError返回NO_ERROR,表示該API仍然成功;否則,GetLastError返回一個不等於NO_ERROR的值。
GetFileSizeEx直接返回BOOL值,表示讀文件是否成功。
◇使用說明
實際上這兩個函數的區別就在於,對文件大小超出DWORD的情況采取不同處理方式。由於歷史原因,GetFileSize用兩個32位值來分別儲存64位文件大小的高位和地位;而GetFileSizeEx直接將文件大小儲存在64位的聯合體中。
>>>本實例使用CreateFile、ReadFile、WriteFile來完成創建、打開、讀寫文件的功能。筆者在實例中自己編寫一個SaveDataToFile函數在D盤根目錄下建立一個show.txt並向文件中寫入數據,並編寫了一個ReadFileContent函數讀取文件的內容。
1 #include <Windows.h> 2 #include <stdio.h> 3 4 DWORD ReadFileContent(LPSTR szFilePath) 5 { 6 //文件大小 7 HANDLE hFileRead; 8 //保存文件大小 9 LARGE_INTEGER liFileSize; 10 //成功讀取的文件數據大小 11 DWORD dwReadedSize; 12 //累加計算已經讀取的數據的大小 13 LONGLONG liTotalRead=0; 14 //文件數據緩存 15 BYTE lpFileDataBuffer[32]; 16 17 //打開已經存在的文件,讀取內容 18 hFileRead = CreateFileA(szFilePath,//name 19 GENERIC_READ, //以讀方式打開 20 FILE_SHARE_READ, //可共享讀 21 NULL, //默認安全設置 22 OPEN_EXISTING, //只打開已經存在的文件 23 FILE_ATTRIBUTE_NORMAL, //常規文件屬性 24 NULL); //無模板 25 //打開文件是否成功 26 if(hFileRead==INVALID_HANDLE_VALUE) 27 { 28 printf("打開文件失敗: %d",GetLastError()); 29 } 30 if(!GetFileSizeEx(hFileRead,&liFileSize)) 31 { 32 printf("獲取文件大小失敗: %d",GetLastError()); 33 } 34 else 35 { 36 printf("文件大小為: %d\n",liFileSize.QuadPart); 37 } 38 //循環讀取並打印內容 39 while(TRUE) 40 { 41 DWORD i; 42 if(!ReadFile(hFileRead,//讀取文件句柄 43 lpFileDataBuffer, //存儲讀取文件內容 44 32, //讀取的大小(字節) 45 &dwReadedSize, //實際讀取的大小 46 NULL)) //不使用Overlapped 47 { 48 printf("讀取文件錯誤: %d\n",GetLastError()); 49 break; 50 } 51 printf("讀取了%d字節,文件內容是: ",dwReadedSize); 52 53 for(i=0;i<dwReadedSize;i++) 54 { 55 printf("0x%x ",lpFileDataBuffer[i]); 56 } 57 printf("\n"); 58 liTotalRead+=dwReadedSize; 59 if(liTotalRead==liFileSize.QuadPart) 60 { 61 printf("讀取文件結束\n"); 62 break; 63 } 64 } 65 CloseHandle(hFileRead); 66 return 0; 67 } 68 69 DWORD SaveDataToFile( 70 LPSTR szFilePath, 71 LPVOID lpData, 72 DWORD dwDataSize) 73 { 74 //文件句柄 75 HANDLE hFileWrite; 76 //成功寫入的數據大小 77 DWORD dwWritedDateSize; 78 //打開已經存在的文件,讀取內容 79 hFileWrite=CreateFileA(szFilePath,//要打開的文件名 80 GENERIC_WRITE,//以寫方式打開開 81 0,//可共享讀 82 NULL,//默認安全設置 83 OPEN_ALWAYS,//打開已經存在的文件 84 FILE_ATTRIBUTE_NORMAL,//常規屬性打開 85 NULL);//無模板 86 //判斷是否成功打開 87 if(hFileWrite==INVALID_HANDLE_VALUE) 88 { 89 printf("打開文件失敗: %d\n",GetLastError()); 90 } 91 //設置文件指針到文件為 92 SetFilePointer(hFileWrite,0,0,FILE_END); 93 //將數據寫入文件 94 if(!WriteFile(hFileWrite,lpData,dwDataSize,&dwWritedDateSize,NULL)) 95 { 96 printf("寫文件失敗: %d\n",GetLastError()); 97 } 98 else 99 { 100 printf("寫文件成功,寫入%d字節。\n",dwWritedDateSize); 101 } 102 CloseHandle(hFileWrite); 103 return 0; 104 } 105 int main() 106 { 107 LPSTR szFileData="這是一個例子"; 108 SaveDataToFile("D:\\show.txt",szFileData,lstrlenA(szFileData)); 109 ReadFileContent("D:\\show.txt"); 110 return 0; 111 }