《精通Windows API-函數、接口、編程實例》——第4章文件系統

第4章文件系統編程

 

 

4.2 磁盤和驅動器管理windows

 

 

 

 

文件系統的基本概念:
包括磁盤分區,卷,目錄,文件對象,文件句柄,文件映射
1.磁盤分區:
物理磁盤,邏輯磁盤
2.卷:
也稱邏輯驅動器,是NTFS,FAT32等文件系統組織結構的最高層.
卷是存儲設備(硬盤)上由文件系統管理的一塊區域,在邏輯上相互隔離的存儲單元.api

windows命名規則:
主文件名+擴展名
windows中文件系統的長度被限制爲260個字符.
這260個字符包括卷標,路徑,主文件名和擴展名,分隔符緩存

在DOS下的保留設備名不能作文件名或主文件名.如CON,PRN,AUX,NUL,COM1.....安全

=================================================================網絡

磁盤和驅動器管理API
GetLogicalDrivers       獲取主機中全部的邏輯驅動器,以Bit Map的形式返回.
GetLogicalDriverString    獲取主機中全部的邏輯驅動器,以驅動器根路徑字符串返回.
FindFirstVolume     查找主機中的第一個驅動器,返回查找句柄.
FindNextVolume      根據FindFirstVolume返回句柄,查找主機中後繼的邏輯驅動器
FindVolumeClose     關閉驅動器查找句柄
GetDriveType      獲取驅動器類型
GetVolumeInformation    獲取邏輯驅動器信息
FindFirstVolumeMountPoint 查找指定卷的第一個掛載點,返回查找句柄
FindNextVolumeMountPoint 根據FindFirstVolumeMountPoint返回的句柄,查找卷的後繼掛載點.
FindVolumeMountPointClose 關閉掛載點查找句柄
GetVolumeNameForVolumeMountPoint 根據指定掛載點獲取相應的卷設備名
SetVolumeMountPoint         將指定卷掛載到指定掛載點處
GetDiskFreeSpace            獲取磁盤空間信息,包括每簇的扇區數,每扇區的字節數,簇數量,空閒的簇數量
GetDiskFreeSpaceEx          獲取用戶可用的空閒空間的字節數,磁盤總容量的字節數
數據結構

文件和目錄管理API
DeleteFile                  刪除參數所指定文件
CopyFile                    複製指定文件爲一個新文件
MoveFile                    將指定文件或目錄移動到指定位置
CreateFile                  新建或打開一個文件,獲取文件句柄
ReadFile                    讀取由文件句柄指定文件的內容
WriteFile                   向由文件句柄指定的文件中寫入內容
GetFileSize                 獲取文件大小,返回DWORD中;大小超出DWORD最大值時可指定高32位的DWORD聯合存儲
GetFileSizeEx               獲取文件大小,存儲到一個64位的大整數聯合體中.
CreateDirectory             建立一個目錄
GetCurrentDirectory         獲取當前程序所在目錄
SetCurrentDirectory         設置當前程序所在目錄
GetModuleFileName           獲取當前模塊全路徑
FindFirstFile               查找指定目錄下第一個文件句柄或目錄,得到查找句柄
FindNextFile                根據FindFirstFile得到的句柄,循環查找文件或目錄
GetFileAttributes           獲取指定文件目錄屬性,返回一個DWORD值
GetFileAttributesEx         獲取文件或目錄屬性,存儲在WIN32_FILE_ATTRIBUTE_DATA結構體中
SetFileAttributes           將文件屬性設定爲指定值
FileTimeToLocalFileTime     將文件時間轉換爲本地時間
FileTimeToSystemTime        將文件轉換爲系統時間,SYSTEMTIME格式便於顯示
app

高級文件操做
CreateFileMapping           建立文件的映射對象
MapViewOfFile               建立視圖,將建立的文件映射對象映射到當前進程的地址空間中
FlushViewOfFile             將視圖中的數據都寫入磁盤,對視圖的操做都會反映到磁盤上的文件中
OpenFileMapping             打開已經存在的命名的文件映射對象
UnmapViewOfFile             取消文件映射
GetMappedFileName           從映射對象獲取被映射文件的文件設備名
QueryDosDevice              獲取MS-DOS設備名
函數

=================================================================學習

2 磁盤和驅動器管理

◇使用兩種方法來遍歷驅動器並獲取驅動器屬性。
◇使用API操做驅動器掛載點。
◇判斷光驅中是否有光盤。
◇獲取磁盤剩餘空間、扇區信息等。

 



 

4.2.1 遍歷卷並獲取屬性

用到的API函數:

 

(1) GetLogicalDrives。
獲取主機中全部的邏輯驅動器,以BitMap的形式返回,其函數原型以下:

(2) GetLogicalDriverStrings。
獲取主機中全部驅動器,以驅動器根路徑字符串返回,其函數原型以下:

(3)FindFirstVolume。
查找主機中的第一個驅動器,返回驅動器設備名,其函數原型以下:

(4)FindNextVolume
查找主機中後繼的邏輯驅動器,其函數原型以下:

(5)FindVo1umeClose。
\關閉FindFirstVolume打開的卷遍歷句柄,其函數原型以下:

(6) GetDriveType。
獲取驅動器類型,其函數原型以下:

(7) GetVolumeInformation。
獲取邏輯驅動器信息,其函數原型以下:

   

 

  1. /* ************************************ 
  2.  *《精通Windows API》  
  3.  * 示例代碼 
  4.  * GetVolumeInfo.c 
  5.  * 4.2.1    遍歷驅動器並獲取驅動器屬性 
  6.  **************************************/  
  7.   
  8. /* 頭文件 */  
  9. #include <windows.h>   
  10. #include <stdlib.h>   
  11. #include <stdio.h>   
  12. #include <string.h>   
  13. /* 預約義 */  
  14. #define BUFSIZE 1024   
  15. /* 函數申明 */  
  16. BOOL GetDirverInfo(LPSTR szDrive);  
  17.   
  18. /* ************************************ 
  19.  * 功能   應用程序主函數,遍歷驅動器並調用 
  20.  *          GetDirverInfo 獲取驅動器屬性 
  21.  **************************************/  
  22. void main(void)  
  23. {  
  24.     CHAR szLogicalDriveStrings[BUFSIZE];  
  25.     PCHAR szDrive;  
  26.   
  27.     ZeroMemory(szLogicalDriveStrings,BUFSIZE);  
  28.     // 獲取邏輯驅動器卷標名   
  29.     GetLogicalDriveStrings(BUFSIZE - 1,szLogicalDriveStrings);    
  30.     szDrive = (PCHAR)szLogicalDriveStrings;  
  31.     // 循環處理每一個卷   
  32.     do  
  33.     {  
  34.         if(!GetDirverInfo(szDrive))  
  35.         {  
  36.             printf("/nGet Volume Information Error: %d", GetLastError());  
  37.         }  
  38.       
  39.       
  40.           
  41.     szDrive += (lstrlen(szDrive)+1);  
  42.     }  
  43.     while(*szDrive!='/x00');  
  44. }  
  45.   
  46. /* ************************************ 
  47.  * BOOL GetDirverInfo(LPSTR szDrive) 
  48.  * 功能   獲取驅動器的屬性 
  49.  * 參數   LPSTR szDrive 
  50.  *  指明要獲取屬性的驅動器的根路徑 如 C:/ 
  51.  * 返回值 BOOL 是否成功 
  52.  **************************************/  
  53. BOOL GetDirverInfo(LPSTR szDrive)  
  54. {     
  55.   
  56.   
  57.     UINT uDriveType;  
  58.     DWORD dwVolumeSerialNumber;  
  59.     DWORD dwMaximumComponentLength;  
  60.     DWORD dwFileSystemFlags;  
  61.     TCHAR szFileSystemNameBuffer[BUFSIZE];  
  62. printf("/n%s/n",szDrive);  
  63.       
  64.     uDriveType = GetDriveType(szDrive);  
  65.     // 判斷類型   
  66.     switch(uDriveType)  
  67.     {  
  68.     case DRIVE_UNKNOWN:  
  69.         printf("The drive type cannot be determined. 未知的磁盤類型  ");  
  70.         break;  
  71.     case DRIVE_NO_ROOT_DIR:  
  72.         printf("The root path is invalid, for example, no volume is mounted at the path. 說明lpRootPathName是無效的  ");  
  73.         break;  
  74.     case DRIVE_REMOVABLE:  
  75.         printf("The drive is a type that has removable media, for example, a floppy drive or removable hard disk. 可移動磁盤 ");  
  76.         break;  
  77.     case DRIVE_FIXED:  
  78.         printf("The drive is a type that cannot be removed, for example, a fixed hard drive. 固定磁盤 ");  
  79.         break;  
  80.     case DRIVE_REMOTE:  
  81.         printf("The drive is a remote (network) drive. 網絡磁盤  ");  
  82.         break;  
  83.     case DRIVE_CDROM:  
  84.         printf("The drive is a CD-ROM drive. 光驅 ");  
  85.         break;  
  86.     case DRIVE_RAMDISK:  
  87.         printf("The drive is a RAM disk. ");  
  88.         break;  
  89.     default:  
  90.         break;  
  91.     }  
  92.     if (!GetVolumeInformation(  
  93.         szDrive, NULL, 0,  
  94.         &dwVolumeSerialNumber,  
  95.         &dwMaximumComponentLength,  
  96.         &dwFileSystemFlags,  
  97.         szFileSystemNameBuffer,  
  98.         BUFSIZE  
  99.         ))  
  100.     {  
  101.         return FALSE;  
  102.     }  
  103.     printf ("/nVolume Serial Number is 存儲驅動器序列號%u",dwVolumeSerialNumber);  
  104.     printf ("/nMaximum Component Length is 文件系統所支持的文件組成部分的最大值%u",dwMaximumComponentLength);  
  105.     printf ("/nSystem Type is文件系統類 %s/n",szFileSystemNameBuffer);  
  106.   
  107.     if(dwFileSystemFlags & FILE_SUPPORTS_REPARSE_POINTS)  
  108.     {  
  109.         printf ("The file system does not support volume mount points./n");  
  110.     }  
  111.     if(dwFileSystemFlags & FILE_VOLUME_QUOTAS)  
  112.     {  
  113.         printf ("The file system supports disk quotas./n");  
  114.     }  
  115.     if(dwFileSystemFlags & FILE_CASE_SENSITIVE_SEARCH)  
  116.     {  
  117.         printf ("The file system supports case-sensitive file names./n");  
  118.     }  
  119.     //you can use these value to get more informaion   
  120.     //   
  121.     //FILE_CASE_PRESERVED_NAMES   
  122.     //FILE_CASE_SENSITIVE_SEARCH   
  123.     //FILE_FILE_COMPRESSION   
  124.     //FILE_NAMED_STREAMS   
  125.     //FILE_PERSISTENT_ACLS   
  126.     //FILE_READ_ONLY_VOLUME   
  127.     //FILE_SUPPORTS_ENCRYPTION   
  128.     //FILE_SUPPORTS_OBJECT_IDS   
  129.     //FILE_SUPPORTS_REPARSE_POINTS   
  130.     //FILE_SUPPORTS_SPARSE_FILES   
  131.     //FILE_UNICODE_ON_DISK   
  132.     //FILE_VOLUME_IS_COMPRESSED   
  133.     //FILE_VOLUME_QUOTAS   
  134.     printf(".../n");  
  135.     return TRUE;  
  136. }  

  

 

 


 


 4.2.2 操做驅動器掛載點

通常能夠用FindFirstVolumeMountPoint系列的API來找到一個卷的全部掛載點;用
GetVolumeNameForVolumeMountPoint來獲取指定掛載點所指向的卷名,卷名形式爲"//?/Volume{GUID}/」;用SetVolumeMountPoint來設置新的掛載點。
經過系統的磁盤管理功能能夠設置卷的掛載點,如圖4-2所示。


◇「個人電腦」圖標右鍵菜單中選擇「管理」。
◇彈出「計算機管理」窗口,選擇「磁盤管理」。
◇選中須要掛載的卷,在右鍵菜單中選擇「更改驅動 器名和路徑」。
◇在彈出的對話框中單擊「添加」按鈕,選擇「裝入 如下空白NTFS文件夾」。
◇選擇須要將卷掛載入的文件夾(空白),單擊「肯定」按鈕。
◇卷就被裝入文件夾中,以後就能夠和訪問文件夾一個訪問這個捲了,如圖4-3和4-4

 

(1)FindFirstVolumeMountPoint.
獲取指定卷的第一個掛載點,函數原型以下:
以用GetLastError()函數獲取更詳細的錯誤信息。
(2) FindNextVolumeMountPoint
查找指定卷的後繼掛載點,函數原型以下:

(3)FindVolumeMountPointClose.
關閉FindVolumeMountPointClose打開的卷句柄,其函數原型以下:
◇參數
hFindVolumeMountPoint:要關閉的掛載點查找句柄。
◇返回值
(4)GetVolumeNameForVolumeMountPoint。
根據指定的掛載點獲取相應的卷設備名,函數原型以下:

(5)SetVolumeMountPc
將指定卷掛載到指定掛載點處,函數原型以下:

  1. /* ************************************ 
  2.  *《Windows應用程序開發》  
  3.  * 示例代碼 
  4.  * mount.c 
  5.  * 4.2.2    卷掛載點操做 
  6.  **************************************/  
  7. /* 預編譯聲明 */  
  8. #define _WIN32_WINNT 0x0501   
  9. #include <windows.h>   
  10. #include <stdio.h>   
  11. #include <tchar.h>   
  12. #define BUFSIZE            MAX_PATH   
  13. #define FILESYSNAMEBUFSIZE MAX_PATH   
  14.   
  15. /* ************************************ 
  16.  * ProcessVolumeMountPoint 
  17.  * 功能   列舉掛載點 
  18.  **************************************/  
  19. BOOL ProcessVolumeMountPoint (HANDLE hPt,  
  20.                               TCHAR *PtBuf, DWORD dwPtBufSize,  
  21.                               TCHAR *Buf)  
  22. {  
  23.     BOOL bFlag;                 // 結果   
  24.     TCHAR Path[BUFSIZE];    // 全路徑   
  25.     TCHAR Target[BUFSIZE];      // 掛載點設備   
  26.   
  27.     printf ("/tVolume mount point found is /"%s/"/n", PtBuf);  
  28.   
  29.     lstrcpy (Path, Buf);  
  30.     lstrcat (Path, PtBuf);  
  31.   
  32.     bFlag = GetVolumeNameForVolumeMountPoint(  
  33.         Path,  Target,  BUFSIZE     );  
  34.   
  35.     if (!bFlag)  
  36.         printf ("/tAttempt to get volume name for %s failed./n", Path);  
  37.     else   
  38.         printf ("/tTarget of the volume mount point is %s./n", Target);  
  39.   
  40.     bFlag = FindNextVolumeMountPoint(  
  41.         hPt,  PtBuf,  dwPtBufSize );  
  42.     return (bFlag);  
  43. }  
  44. /* ************************************ 
  45.  * ProcessVolume 
  46.  * 功能   判斷卷類型,列舉掛載點 
  47.  **************************************/  
  48. BOOL ProcessVolume (HANDLE hVol, TCHAR *Buf, DWORD iBufSize)  
  49. {  
  50.     BOOL bFlag;           // 返回標誌   
  51.     HANDLE hPt;           // 卷句柄   
  52.     TCHAR PtBuf[BUFSIZE]; // 掛載點路徑   
  53.     DWORD dwSysFlags;     // 文件系統標記   
  54.     TCHAR FileSysNameBuf[FILESYSNAMEBUFSIZE];  
  55.   
  56.     printf ("Volume found is /"%s/"./n", Buf);  
  57.   
  58.     // 是否NTFS   
  59.     GetVolumeInformation( Buf, NULL, 0, NULL, NULL,  
  60.         &dwSysFlags, FileSysNameBuf,   
  61.         FILESYSNAMEBUFSIZE);  
  62.   
  63.     if (! (dwSysFlags & FILE_SUPPORTS_REPARSE_POINTS))   
  64.     {  
  65.         printf ("/tThis file system does not support volume mount points./n");  
  66.     }   
  67.     else   
  68.     {  
  69.         // 本卷中的掛載點   
  70.         hPt = FindFirstVolumeMountPoint(  
  71.             Buf, // 卷的跟跟蹤   
  72.             PtBuf, // 掛載點路徑   
  73.             BUFSIZE   
  74.             );  
  75.   
  76.         if (hPt == INVALID_HANDLE_VALUE)  
  77.         {  
  78.             printf ("/tNo volume mount points found!/n");  
  79.         }   
  80.         else   
  81.         {  
  82.             // 處理掛載點   
  83.             bFlag = ProcessVolumeMountPoint (hPt,   
  84.                 PtBuf,   
  85.                 BUFSIZE,   
  86.                 Buf);  
  87.             // 循環   
  88.             while (bFlag)   
  89.                 bFlag =   
  90.                 ProcessVolumeMountPoint (hPt, PtBuf, BUFSIZE, Buf);  
  91.             // 結束   
  92.             FindVolumeMountPointClose(hPt);  
  93.         }  
  94.     }  
  95.   
  96.     // 下一個   
  97.     bFlag = FindNextVolume(  
  98.         hVol, Buf,  iBufSize);  
  99.   
  100.     return (bFlag);   
  101. }  
  102. /* ************************************ 
  103.  * int GetMountPoint(void) 
  104.  * 功能   獲取掛載點 
  105.  **************************************/  
  106. int GetMountPoint(void)  
  107. {  
  108.     TCHAR buf[BUFSIZE];     // 卷標識符   
  109.     HANDLE hVol;                    // 卷句柄   
  110.     BOOL bFlag;                 // 結果標誌   
  111.   
  112.     printf("Volume mount points info of this computer:/n/n");  
  113.     // 打開卷   
  114.     hVol = FindFirstVolume (buf, BUFSIZE );  
  115.     if (hVol == INVALID_HANDLE_VALUE)  
  116.     {  
  117.         printf ("No volumes found!/n");  
  118.         return (-1);  
  119.     }  
  120.   
  121.     bFlag = ProcessVolume (hVol, buf, BUFSIZE);  
  122.     while (bFlag)   
  123.     {  
  124.         bFlag = ProcessVolume (hVol, buf, BUFSIZE);  
  125.     }  
  126.   
  127.     bFlag = FindVolumeClose(    hVol );  
  128.     return (bFlag);  
  129. }  
  130.   
  131. /* ************************************ 
  132.  * void Usage (PCHAR argv) 
  133.  * 功能   使用方法 
  134.  **************************************/  
  135. void Usage (PCHAR argv)  
  136. {  
  137.     printf( "/n/n/t%s, mount a volume at a mount point./n", argv );  
  138.     printf( "/tFor example, /"mount D://mnt//drives// E:///"/n" );   
  139. }  
  140.   
  141. /* ************************************ 
  142.  *  main 
  143.  * 功能   入口函數 
  144.  **************************************/  
  145. int main( int argc, PCHAR argv[] )  
  146. {  
  147.     BOOL bFlag;  
  148.     CHAR Buf[BUFSIZE];       
  149.   
  150.     if( argc != 3 )   
  151.     {  
  152.         GetMountPoint();  
  153.         Usage( argv[0] );  
  154.         return( -1 );  
  155.     }  
  156.   
  157.     bFlag = GetVolumeNameForVolumeMountPoint(  
  158.         argv[2],        // 輸入掛載點或目錄   
  159.         Buf,                // 輸出卷名   
  160.         BUFSIZE  
  161.         );  
  162.   
  163.     if (bFlag != TRUE)   
  164.     {  
  165.         printf( "Retrieving volume name for %s failed./n", argv[2] );  
  166.         return (-2);  
  167.     }  
  168.   
  169.     printf( "Volume name of %s is %s/n", argv[2], Buf );  
  170.     bFlag = SetVolumeMountPoint(  
  171.         argv[1],    // 掛載點   
  172.         Buf         // 須要掛載的卷   
  173.         );  
  174.   
  175.     if (!bFlag)  
  176.     {  
  177.         printf ("Attempt to mount %s at %s failed. error code is/n",   
  178.             argv[2], argv[1], GetLastError());  
  179.     }  
  180.   
  181.     return (bFlag);  
  182. }  

 


 


4.2.3 判斷光驅中是否有光盤

 判斷光驅中是否有光盤,仍然可使用在4.2.1小節介紹的GetDriveType和GetVolumeInformation函數實現。首先使用驅動器根路徑做爲GetDriveType和參數,若是返回值是DRIVE_CDROM,則說明此驅動器爲光驅。而後使用GetVolumeInformation獲取信息,若是成功,則說明存光盤已經放入。調用完成後GetVolumeInformation函數的第7個參數LPTSTR lpFileSystemNameBuffer存儲的是文件系統的類別字符串,光盤通常是CDFS。若是調用GetVolumeInformation時返回FALSE,而且GetLastError返回21,則說明驅動器中未放入光盤。
1.關鍵API
(1)GetDiskType與GetVolumeInformation。
這兩個API已經在4.2.1小節介紹過,這裏再也不贅述。
(2)GetLastError。
獲取在執行中本線程最近的一次錯誤。本函數是不少系統API返回執行錯誤緣由的方法。可能使用SetLastError函數設置本線程的Last-Error值。GetLastError函數原型以下:
  1.  * 4.2.3    判斷光驅中是否有光盤  
  2.  **************************************/  
  3. /* 頭文件 */  
  4. #include <windows.h>   
  5. #include <stdio.h>   
  6. #include <tchar.h>   
  7. /* 預約義 */  
  8. #define BUFSIZE            512   
  9.   
  10. /* ************************************ 
  11.  * int main( int argc, PCHAR argv[] ) 
  12.  * 功能   應用程序主函數,根據輸入的驅動器 
  13.  *      根路徑參數判斷是否爲光驅,是否放 
  14.  *      入光盤。 
  15.  * 參數   驅動器根路徑,好比「D:/」。 
  16.  **************************************/  
  17.   
  18. int main( int argc, PCHAR argv[] )  
  19. {  
  20.     //存儲文件系統類別名   
  21.     CHAR szFileSystemNameBuffer[BUFSIZE];  
  22.     DWORD dwLastError;  
  23.     DWORD dwFileSystemFlags;  
  24.   
  25.     //判斷是否輸入運行時參數   
  26.     if( argc != 2 )   
  27.     {  
  28.         printf("請輸入驅動器的根路徑,好比: /"D:///"/n");   
  29.         return( -1 );  
  30.     }  
  31.       
  32.     //判斷輸入的驅動器是否爲CD/DVD ROM   
  33.     if(GetDriveType(argv[1])!=DRIVE_CDROM)  
  34.     {  
  35.         printf("驅動器 %s 不是 CD/DVD ROM。/n",argv[1]);  
  36.         return( -1 );  
  37.     }  
  38.       
  39.     //獲取卷信息   
  40.     if (!GetVolumeInformation(  
  41.         argv[1], NULL, 0,  
  42.         NULL,NULL,  
  43.         &dwFileSystemFlags,  
  44.         szFileSystemNameBuffer,  
  45.         BUFSIZE  
  46.         ))  
  47.     {  
  48.         dwLastError = GetLastError();  
  49.         if(dwLastError == 21)  
  50.         {  
  51.             printf("設備未就緒,請放入光盤!/n");  
  52.             return 0;  
  53.         }  
  54.         else  
  55.         {  
  56.             printf("GetVolumeInformation 錯誤 %d/n",dwLastError);  
  57.             return 0;  
  58.         }  
  59.     }  
  60.     printf ("光盤已經放入,文件系統類別 %s。/n",szFileSystemNameBuffer);  
  61.     return 0;  
  62. }  


4.2.4 獲取磁盤分區的總容量、空閒容量、簇、扇區信息

獲取磁盤分區的總容量和空閒空間的容量可使用GetDiskFreeSpace函數或GetDiskFree SpaceEx函數。GetDiskFreeSpace使用DWORD類型做爲輸出參數,因爲DWOR長度爲32位,最大隻能表示4GB,而通常的磁盤分區大小都大於4GB,因此,GetDiskFreeSpace並不直接返回磁盤的總容量和空閒空間的容量,而是使用總簇數、空閒的簇數、每簇的扇區數、每扇區的字節數來表示。用戶在編程時,可使用它們的乘積來得到最終結果。而GetDiskFreeSpaceEx使用ULARGE_INTEGER (DWORD64)類型的數據來存儲磁盤空間總空間和剩餘空間,因此能夠直接得到結果。DWORD64能夠表示約16777216TB的數據量(DWORD64最大可表示2Byte,lTB=2Byte,

(2)GetDiskFreeSpacEX。
獲取驅動器根路徑做爲輸入,獲取用戶可用的空閒空間的字節數、空閒空間的字節數、磁盤總容量的字節數,其函數原型以下:

2.關鍵數據結構
GetDiskFreeSpaceEx函數使用到了數據結構ULARGE_INTEGER,數據類型PULARGE
INTEGER是指向它的指針。ULARGE__ INTEGER的定義以下,此數據結構使用兩個DWORD來表
示64位數據。低位存儲於前,高位存儲於後,與DWORD64的存儲形式是一致的,因此能夠直接強制類型轉換爲DOWRD64類型。也能夠直接使用QuadPart成員,QuadPart成員是ULONGLONG形數據結構,在通常32位主機上,與DWORD64具備一樣的長度。

  1. /* ************************************ 
  2.  *《精通Windows API》  
  3.  * 示例代碼 
  4.  * diskspace.c 
  5.  * 4.2.4    獲取磁盤空間信息 
  6.  **************************************/  
  7.   
  8. /* 頭文件 */  
  • #include <windows.h>   
  • #include <stdio.h>   
  •   
  • /* ************************************ 
  •  * BOOL GetDiskSpaceInfo(LPCSTR pszDrive 
  •  * 功能   根據輸入的驅動器,獲取磁盤總容量 
  •  *          空閒空間、簇數量等磁盤信息 
  •  * 參數   驅動器根路徑,好比「D:/」。 
  •  **************************************/  
  • BOOL GetDiskSpaceInfo(LPCSTR pszDrive)  
  • {  
  •     DWORD64 qwFreeBytesToCaller, qwTotalBytes, qwFreeBytes;  
  •     DWORD dwSectPerClust, dwBytesPerSect, dwFreeClusters,  dwTotalClusters;  
  •     BOOL bResult;  
  •       
  •     //使用GetDiskFreeSpaceEx獲取磁盤信息並打印結果   
  •     bResult = GetDiskFreeSpaceEx (pszDrive,  
  •         (PULARGE_INTEGER)&qwFreeBytesToCaller,  
  •         (PULARGE_INTEGER)&qwTotalBytes,  
  •         (PULARGE_INTEGER)&qwFreeBytes);  
  •   
  •     if(bResult)   
  •     {  
  •         printf("使用GetDiskFreeSpaceEx獲取磁盤空間信息/n");  
  •         printf("可得到的空閒空間(字節): /t%I64d/n", qwFreeBytesToCaller);  
  •         printf("空閒空間(字節): /t/t%I64d/n", qwFreeBytes);  
  •         printf("磁盤總容量(字節): /t/t%I64d/n", qwTotalBytes);  
  •     }  
  •   
  •     //使用GetDiskFreeSpace獲取磁盤信息並打印結果   
  •     bResult = GetDiskFreeSpace (pszDrive,   
  •         &dwSectPerClust,   
  •         &dwBytesPerSect,  
  •         &dwFreeClusters,   
  •         &dwTotalClusters);  
  •   
  •     if(bResult)   
  •     {  
  •         printf("/n使用GetDiskFreeSpace獲取磁盤空間信息/n");  
  •         printf("空閒的簇數量 : /t/t/t%d/n",dwFreeClusters);  
  •         printf("總簇數量 : /t/t/t%d/n",dwTotalClusters);  
  •         printf("每簇的扇區數量 : /t/t%d/n",dwSectPerClust);  
  •         printf("每扇區的容量(字節): /t/t%d/n",dwBytesPerSect);  
  •         printf("空閒空間(字節): /t/t%I64d/n",   
  •             (DWORD64)dwFreeClusters*  
  •             (DWORD64)dwSectPerClust*(DWORD64)dwBytesPerSect);  
  •         printf("磁盤總容量(字節): /t/t%I64d",  
  •             (DWORD64)dwTotalClusters*  
  •             (DWORD64)dwSectPerClust*(DWORD64)dwBytesPerSect);  
  •     }  
  •     return bResult;  
  • }  
  •   
  • /* ************************************ 
  •  * int main( int argc, PCHAR argv[] ) 
  •  * 功能   應用程序主函數,根據輸入參數 
  •  *          調用GetDiskSpaceInfo函數獲取 
  •  *          磁盤空間信息 
  •  * 參數   驅動器根路徑,好比「D:/」。 
  •  **************************************/  
  • int main(int argc, PCHAR argv[])  
  • {  
  •     GetDiskSpaceInfo (argv[1]);  
  • }  

 

 



 

4.3 文件和目錄管理


文件和目錄管理是Windows系統編程最爲基本的內容,幾乎全部的應用程序都會使用到文件和目錄的操做。本節將向讀者演示如何建立目錄、遍歷目錄、建立文件、打開文件、讀寫文件、移動複製刪除文件等。本節經過如下多個實例來說解Windows API對文件和目錄的管理。
◇刪除、複製、重命名、移動文件。
◇建立、打開、讀寫文件。
◇建立、打開目錄。
◇獲取當前目錄、獲取程序所在的目錄、獲取模塊路徑。
◇查找文件、遍歷目錄下的文件和子目錄。
◇遞歸遍歷目錄樹。

◇獲取、設置文件屬性和時間。


4.3.1 刪除、複製、重命名、移動文件


Windows系統爲文件的刪除、複製、重命名或移動文件提供了相應的API函數。刪除文件使用DeleteFile函數;複製文件使用CopyFile函數;重命名文件和移動文件實際是一個操做,使用MoveFile函數。這幾個函數的使用都很是簡單,下面分別介紹。
1.關鍵API
(1) DeleteFile。

DeleteFile的功能是刪除文件。以文件路徑做爲輸入,指向須要刪除的文件。文件路徑能夠是相似於「c:/files/delete.txt」的絕對路徑,也能夠是相似於「./delete.txt」的相對路徑,二相對於可執行文件所在的路徑。

(2) CopyFile。
CopyFile的功能是複製文件。經過參數輸入複製文件和源路徑和目的路徑,路徑能夠是絕對路徑也能夠是相對路徑,還能夠經過參數指明若是目的路徑已經存在文件,是否覆蓋。可使用CopyFileEx函數進行更爲高級的操做,好比在複製進行過程當中取消複製等。CopyFileEx能夠指定
一個回調函數來處理文件複製中所可能發生的各類狀況。

3) MoveFile。
MoveFile的功能是移動、重命名文件和目錄。經過參數輸入源路徑和目的路徑,路徑能夠是絕對路徑也能夠是相對路徑,若是目的路徑的文件或目錄已經存在,則返回失敗。可使用MoveFileEx函數來指定更多的選項,若是已經存在是否替換等。還可使用MoveFileWithProgress指定一個回調函數來處理文件移動中所可能發生的各類狀況。函數原型以下:

(4) CopyFileEx、MoveFileEx以及MoveFileWithProgreSS.
這3個API函數功能更豐富,可是限於篇幅這裏再也不作詳細介紹,讀者可使用SDK文檔學習它們的使用方法。

 

 

  1. /* ************************************ 
  2. *《精通Windows API》  
  3. * 示例代碼 
  4. * wr.c 
  5. * 4.3.2 建立、打開、讀寫文件,獲取文件大小 
  6. **************************************/  
  7.   
  8. /* 頭文件 */  
  • #include <windows.h>   
  • #include <stdio.h>   
  •   
  • /* ************************************ 
  • * DWORD ReadFileContent(LPSTR szFilePath) 
  • * 功能    獲取文件大小 
  • *       讀取文件內容,並以16進制的形式打印出來 
  • * 參數    LPSTR szFilePath 
  • *       文件路徑 
  • **************************************/  
  • DWORD ReadFileContent(LPSTR szFilePath)  
  • {  
  •     //文件大小   
  •     HANDLE hFileRead;  
  •     //保存文件大小   
  •     LARGE_INTEGER liFileSize;  
  •     //成功讀取的文件數據大小   
  •     DWORD dwReadedSize;  
  •     //累加計算已經讀取數據的大小   
  •     LONGLONG liTotalRead = 0;  
  •     //文件數據緩存   
  •     BYTE lpFileDataBuffer[32];  
  •   
  •     //打開已經存在的文件,讀取內容。      
  •     hFileRead = CreateFile(szFilePath,// 要打開的文件名   
  •         GENERIC_READ,              // 以讀方式打開   
  •         FILE_SHARE_READ,           // 可共享讀   
  •         NULL,                      // 默認安全設置   
  •         OPEN_EXISTING,             // 只打開已經存在的文件   
  •         FILE_ATTRIBUTE_NORMAL,     // 常規文件屬性   
  •         NULL);                     // 無模板   
  •   
  •     //打開文件是否成功。   
  •     if(hFileRead==INVALID_HANDLE_VALUE)  
  •     {  
  •         printf("打開文件失敗:%d",GetLastError());  
  •     }  
  •   
  •     if(!GetFileSizeEx(hFileRead,&liFileSize))  
  •     {  
  •         printf("獲取文件大小失敗:%d",GetLastError());  
  •     }  
  •     else  
  •     {  
  •         printf("文件大小爲:%d/n",liFileSize.QuadPart);  
  •     }  
  •   
  •     //循環讀取並打印文件內容   
  •     while(TRUE)  
  •     {  
  •         DWORD i;  
  •   
  •         if(!ReadFile(hFileRead, //讀文件的句柄   
  •             lpFileDataBuffer,   //存儲讀取的文件內容   
  •             32,                 //讀的大小(字節)   
  •             &dwReadedSize,      //實際讀取的大小   
  •             NULL))              //不使用Overlapped   
  •         {  
  •             printf("讀文件錯誤:%d/n",GetLastError());  
  •             break;  
  •         }  
  •         printf("讀取了%d字節,文件內容是:",dwReadedSize);  
  •           
  •         for(i=0; i<dwReadedSize; i++)  
  •         {  
  •             printf("0x%x ",lpFileDataBuffer[i]);  
  •         }  
  •         printf("/n");  
  •         liTotalRead += dwReadedSize;  
  •         if(liTotalRead == liFileSize.QuadPart)  
  •         {  
  •             printf("讀文件結束/n");  
  •             break;  
  •         }  
  •     }  
  •     CloseHandle(hFileRead);  
  •     return 0;  
  • }  
  •   
  • /* ************************************ 
  • *  SaveDataToFile 
  • * 功能    將數據存儲到文件末尾 
  • * 參數    LPSTR szFilePath    文件路徑 
  • *       LPVOID lpData       需存儲的數據 
  • *       DWORD dwDataSize    數據大小(字節) 
  • **************************************/  
  • DWORD SaveDataToFile(  
  •                      LPSTR szFilePath,  
  •                      LPVOID lpData,  
  •                      DWORD dwDataSize)  
  • {  
  •     //文件句柄   
  •     HANDLE hFileWrite;  
  •     //成功寫入的數據大小   
  •     DWORD dwWritedDateSize;  
  •   
  •     //打開已經存在的文件,讀取內容。      
  •     hFileWrite = CreateFile(szFilePath, // 要打開的文件名   
  •         GENERIC_WRITE,          // 以寫方式打開   
  •         0,                      // 可共享讀   
  •         NULL,                   // 默認安全設置   
  •         OPEN_ALWAYS,            // 打開已經存在的文件,沒用則建立   
  •         FILE_ATTRIBUTE_NORMAL,  // 常規文件屬性   
  •         NULL);                  // 無模板   
  •       
  •     //判斷是否打開成功   
  •     if(hFileWrite==INVALID_HANDLE_VALUE)  
  •     {  
  •         printf("打開文件失敗:%d/n",GetLastError());  
  •     }  
  •   
  •     //設置文件指針到文件尾   
  •     SetFilePointer(hFileWrite,0,0,FILE_END);  
  •   
  •     //將數據寫入文件   
  •     if(!WriteFile(hFileWrite,lpData,dwDataSize,&dwWritedDateSize,NULL))  
  •     {  
  •         printf("寫文件失敗:%d/n",GetLastError());  
  •     }  
  •     else  
  •     {  
  •         printf("寫文件成功,寫入%d字節。/n",dwWritedDateSize);  
  •     }  
  •     CloseHandle(hFileWrite);  
  •     return 0;  
  • }  
  •   
  • /* ************************************ 
  • * int main(void) 
  • * 功能    演示使用SaveDataToFile和ReadFileContent函數 
  • **************************************/  
  • int main(void)  
  • {  
  •     LPSTR szFileData = "這是一個例子";  
  •     SaveDataToFile("C://show.txt",szFileData,lstrlen(szFileData));  
  •     ReadFileContent("C://show.txt");  
  •     return 0;  
  • }  

 


 

 


 

4.3.2 建立、打開、讀寫文件,獲取文件大小

在Windows系統中,建立和打開文件都是使用API函數CreateFile,CreateFile經過指定不一樣的參數來表示是新建一個文件,打開已經存在的文件,仍是從新創建文件等。讀寫文件最爲直接的方式是使用ReadFile和WriteFile函數,也可使用文件鏡像,獲取文件大小通常使用GetFileSize函數,也可使用GetFileAttributesEx等函數(在4.3.7節介紹)。讀寫文件、獲取文件大小以前都須要使用CreateFile建立或打開的文件,得到文件句柄。
在文件操做中,文件句柄是一個關鍵的概念。文件句柄唯一標識了一個文件,ReadFile、
WriteFile、GetFileSize等函數是使用文件句柄做爲參數來表示,用戶須要讀、寫、獲取大小的文件是哪個文件。在對文件進行操做前,都必需要使用CreateFile得到文件句柄。

 

1.關鍵API
(1)CreateFile
CreateFile是文件操做中最主要的一個函數。幾乎全部的文件操做都須要使用到文件句柄。而CreateFile函數爲這些操做創建文件句柄。CreateFile函數定義以下:

(2)ReadFile。

ReadFile動能是從文件中讀出數據。須要使用CreateFile所返回的文件句柄。函數原型以下:

(3)WriteFile。
WriteFile函數的功能是將數據寫入到文件中,寫入到文件指針所在的位置,寫入操做完成後,文件指針會移動到寫入的數據以後,函數原型以下:

(4)GetFileSize、GetFileSizeEX.
GetFileSize、GetFileSizeEX的功能是一致的,都是獲取文件大小,函數原型分別以下。

  1. /* ************************************ 
  2.  *《精通Windows API》  
  3.  * 示例代碼 
  4.  * files.c 
  5.  * 4.3.1    刪除、複製、重命名、移動文件 
  6.  **************************************/  
  7.   
  8. /* 頭文件 */  
  9. #include <windows.h>   
  10. #include <stdio.h>   
  11.   
  12. /* ************************************ 
  13.  * int main( int argc, PCHAR argv[] ) 
  14.  * 功能   應用程序主函數,根據輸入參數 
  15.  *      刪除、複製、重命名文件 
  16.  * 
  17.  * 參數   刪除文件: 
  18.  *          -d 文件路徑 
  19.  *      將文件路徑1的文件複製到文件路徑2: 
  20.  *          -c 文件路徑1 文件路徑2 
  21.  *      將文件路徑1的文件移動、重命名爲文件路徑2的文件 
  22.  *          -m 文件路徑1 文件路徑2 
  23.  **************************************/  
  24. int main(int argc, PCHAR argv[])  
  25. {  
  26.     LPSTR y="c:/2.bat";  
  27. LPSTR x="c:/1.bat";  
  28.     //-d參數,刪除文件。   
  29.     if(0==lstrcmp("-d",argv[1]) && argc==3)  
  30.     {  
  31.         if(!DeleteFile(argv[2]))  
  32.         {  
  33.             printf("刪除文件錯誤:%x/n",GetLastError());  
  34.         }  
  35.         else  
  36.         {  
  37.             printf("刪除成功!/n");  
  38.         }  
  39.     }  
  40.     //-c參數,複製文件。   
  41.     //若是文件存在,詢問用戶是否覆蓋   
  42.     else if(0==lstrcmp("-c",argv[1]) && argc==4)  
  43.     {  
  44.         //複製,不覆蓋已經存在的文件   
  45.         if(!CopyFile(argv[2],argv[3],TRUE))  
  46.         {  
  47.             //LastError == 0x50,文件存在。   
  48.             if(GetLastError() == 0x50)  
  49.             {  
  50.                 printf("文件%s已經存在,是否覆蓋?y/n:",argv[3]);  
  51.                 if('y'==getchar())  
  52.                 {  
  53.                     //複製,覆蓋已經存在的文件。   
  54.                     if(!CopyFile(argv[2],argv[3],FALSE))  
  55.                     {  
  56.                         printf("複製文件錯誤,%d/n",GetLastError());  
  57.                     }  
  58.                     else  
  59.                     {  
  60.                         printf("複製成功!/n");  
  61.                     }  
  62.                 }  
  63.                 else  
  64.                 {  
  65.                     return 0;  
  66.                 }  
  67.             }  
  68.         }  
  69.         else  
  70.         {  
  71.             printf("複製成功!/n");  
  72.         }  
  73.     }  
  74.     //-m參數,移動、重命名文件。   
  75.     else if(0==lstrcmp("-m",argv[1]) && argc==4)  
  76.     {  
  77.         if(!MoveFile( x,y))  
  78.         {  
  79.             printf("移動文件錯誤:%d/n",GetLastError());  
  80.         }  
  81.         else  
  82.         {  
  83.             printf("移動文件成功!/n");  
  84.         }  
  85.     }  
  86.     else  
  87.     {  
  88.         printf("參數錯誤!/n");  
  89.     }  
  90. }  



 4.3.3 建立目錄

編程實現建立目錄是很是簡單的,只要使用API函數CreateDirectory便可。
1. 關鍵API
(1) Createdirectory
函數原型以下:
◇參數
lpPathName:輸入參數,所要建立的目錄名或路徑。
lpSecurityAttributes:輸入參數,設置爲NULL。
◇返回值
返回BOOL值,表示是否成功。
◇使用說明
若是程序返回失敗,可使用GetLastError函數獲取錯誤信息。可能的值包括ERROR
ALREADY EXISTS(文件夾已經存在)和ERROR PATH NOT FOUND(路徑不存在)。

  1. /* ************************************ 
  2. *《精通Windows API》  
  3. * 示例代碼 
  4. * dir.c 
  5. * 4.3.3 建立目錄 
  6. **************************************/  
  7.   
  8. /* 頭文件 */  
  9. #include <windows.h>   
  10. #include <stdio.h>   
  11.   
  12. /* ************************************ 
  13. * int main(void) 
  14. * 功能    演示使用CreateDirectory建立目錄 
  15. **************************************/  
  16. int main(void)  
  17. {  
  18.     //在程序的當前目錄下建立「sub_dir」子目錄   
  19.     LPSTR szDirPath = "sub_dir";  
  20.     if (!CreateDirectory(szDirPath, NULL))   
  21.     {   
  22.         printf("建立目錄 %s 錯誤。/n",szDirPath);   
  23.         return 1;  
  24.     }  
  25.   
  26.     //在C盤下建立目錄「example_dir」   
  27.     szDirPath = "C://example_dir";  
  28.     if (!CreateDirectory(szDirPath, NULL))   
  29.     {   
  30.         printf("建立目錄 %s 錯誤。/n",szDirPath);   
  31.         return 1;  
  32.     }   
  33.     printf("成功/n");   
  34.   
  35.     return 0;  
  36. }  

 


 


 4.3.4 獲取程序所在的目錄、程序模塊路徑,獲取和設置當前目錄


Windows系統提供一組API實現對程序運行時相關目錄的獲取和設置。用戶可使用
GetCurrentDirectory和SetCurrentDirectory獲取程序的當前目錄,獲取模塊的路徑使用
GetModuleFileName,若是以NULL參數調用GetModuleFileName,將會返回當前模塊的路徑。若是在程序主模塊(exe)中獲取當前模塊路徑,即可以從當前模塊的路徑中提取出程序運行時所在的路徑。
1.關鍵API
(1)GetCurrentDirectory。
獲取進程的當前目錄,函數原型以下:

 (2)SetCurrentDirectory。
設置進程的當前目錄,函數原型以下:

(3)GetModuleFileName。
獲取模塊文件名,當第一個參數爲NULL時獲取當前模塊路徑,函數原型以下:

  1. /* ************************************ 
  2. *《精通Windows API》  
  3. * 示例代碼 
  4. * cur_mod_dir.c 
  5. * 4.3.4 獲取當前目錄、獲取程序所在的目錄、獲取模塊路徑 
  6. **************************************/  
  7.   
  8. /* 頭文件 */  
  9. #include <windows.h>   
  10. #include <stdio.h>   
  11.   
  12. /* ************************************ 
  13. * int main(void) 
  14. * 功能    演示使用設置獲取當前路徑 
  15. *       演示獲取模塊路徑 
  16. **************************************/  
  17. int main(void)  
  18. {  
  19.     //用於存儲當前路徑   
  20.     CHAR szCurrentDirectory[MAX_PATH];  
  21.     //用於存儲模塊路徑   
  22.     CHAR szMoudlePath[MAX_PATH];  
  23.     //Kernel32文件名與句柄   
  24.     LPSTR szKernel32 = "kernel32.dll";  
  25.     HMODULE hKernel32;  
  26.     //當前路徑的長度,也用於判斷獲取是否成功   
  27.     DWORD dwCurDirPathLen;  
  28.       
  29.     //獲取進程當前目錄   
  30.     dwCurDirPathLen =   
  31.         GetCurrentDirectory(MAX_PATH,szCurrentDirectory);  
  32.     if(dwCurDirPathLen == 0)  
  33.     {  
  34.         printf("獲取當前目錄錯誤。/n");   
  35.         return 0;  
  36.     }  
  37.     printf("進程當前目錄爲 %s /n",szCurrentDirectory);   
  38.       
  39.     //將進程當前目錄設置爲「C:/」   
  40.     lstrcpy(szCurrentDirectory, "C://");  
  41.     if(!SetCurrentDirectory(szCurrentDirectory))  
  42.     {  
  43.         printf("設置當前目錄錯誤。/n");   
  44.         return 0;  
  45.     }  
  46.     printf("已經設置當前目錄爲 %s /n",szCurrentDirectory);   
  47.   
  48.     //在當前目錄下建立子目錄「current_dir」   
  49.     //運行完成後C:盤下將出現文件夾「current_dir」   
  50.     CreateDirectory("current_dir", NULL);  
  51.   
  52.     //再次獲取系統當前目錄   
  53.     dwCurDirPathLen =   
  54.         GetCurrentDirectory(MAX_PATH,szCurrentDirectory);  
  55.     if(dwCurDirPathLen == 0)  
  56.     {  
  57.         printf("獲取當前目錄錯誤。/n");   
  58.         return 0;  
  59.     }  
  60.     printf("GetCurrentDirectory獲取當前目錄爲 %s /n",  
  61.         szCurrentDirectory);   
  62.   
  63.     //使用NULL參數,獲取本模塊的路徑。   
  64.     if(!GetModuleFileName(NULL,szMoudlePath,MAX_PATH))  
  65.     {  
  66.         printf("獲取模塊路徑錄錯誤。/n");   
  67.         return 0;  
  68.     }  
  69.     printf("本模塊路徑 %s /n",szMoudlePath);  
  70.   
  71.     //獲取Kernel32.dll的模塊句柄。   
  72.     hKernel32 = LoadLibrary(szKernel32);  
  73.   
  74.     //使用Kernel32.dll的模塊句柄,獲取其路徑。   
  75.     if(!GetModuleFileName(hKernel32,szMoudlePath,MAX_PATH))  
  76.     {  
  77.         printf("獲取模塊路徑錯誤。/n");   
  78.         return 0;  
  79.     }  
  80.     printf("kernel32模塊路徑 %s /n",szMoudlePath);   
  81.   
  82.     return 0;  
  83. }  

 

 



 

 

4.3.5 查找文件、遍歷指定目錄下的文件和子目錄

Windows API中,有一組專門的函數和結構,用於遍歷目錄,它們是FindFirstFile函數、
FindNextFile函數和WIN32_FIND_DATA結構。使用FindFirstFile和FindNextFile函數並與do-while循環結合,能夠完成遍歷目錄的任務,詳見實例4-10。
值得一提的是,FindFirstFile輸入參數的路徑需使用通配符,也就是用戶能夠根據一些條件來對查找的文件做簡單的過濾。實例4-10講解查找特定目錄下的全部文件和文件夾。讀者可根據本身的須要,指定查找文件的條件。
1.關鍵API
(1)FindFirstFile。
查找第一個目錄或文件,獲取查找句柄,函數原型以下:

(2)FindNextFile
對文件、文件夾進行循環查找,函數原型以下:

2.關鍵結構
WIN32_FIND_DATA結構用於表示找到的文件,結構中包括文件、目錄的名字,建立、最後訪問和最後寫入時間,文件大小、文件屬性等。

  1. /* ************************************ 
  2. *《精通Windows API》  
  3. * 示例代碼 
  4. * sub_dir.c 
  5. * 4.3.5 遍歷目錄下的文件和子目錄 
  6. **************************************/  
  7.   
  8. /* 頭文件 */  
  9. #include <windows.h>   
  10. #include <stdio.h>   
  11.   
  12. /* ************************************ 
  13. * DWORD EnumerateFileInDrectory(LPSTR szPath) 
  14. * 功能    遍歷目錄下的文件和子目錄,將顯示文件的 
  15. *       文件和文件夾隱藏、加密的屬性 
  16. * 參數    LPTSTR szPath,爲需遍歷的路徑 
  17. * 返回值   0表明執行完成,1代碼發生錯誤 
  18. **************************************/  
  19. DWORD EnumerateFileInDrectory(LPSTR szPath)  
  20. {  
  21.     WIN32_FIND_DATA FindFileData;  
  22.     HANDLE hListFile;  
  23.     CHAR szFilePath[MAX_PATH];  
  24.       
  25.     //構造表明子目錄和文件夾路徑的字符串,使用通配符「*」   
  26.     lstrcpy(szFilePath, szPath);      
  27.     //註釋的代碼能夠用於查找全部以「.txt結尾」的文件。   
  28.     //lstrcat(szFilePath, "//*.txt");   
  29.     lstrcat(szFilePath, "//*");  
  30.     //查找第一個文件/目錄,得到查找句柄   
  31.     hListFile = FindFirstFile(szFilePath,&FindFileData);  
  32.     //判斷句柄   
  33.     if(hListFile==INVALID_HANDLE_VALUE)  
  34.     {  
  35.         printf("錯誤:%d",GetLastError());  
  36.         return 1;  
  37.     }  
  38.     else  
  39.     {         
  40.         do  
  41.         {  
  42.             /*  若是不想顯示錶明本級目錄和上級目錄的「.」和「..」,  
  43.                 可使用註釋部分的代碼過濾。  
  44.             if(lstrcmp(FindFileData.cFileName,TEXT("."))==0||  
  45.                 lstrcmp(FindFileData.cFileName,TEXT(".."))==0)  
  46.             {  
  47.                 continue;  
  48.             }  
  49.             */  
  50.             //打印文件名、目錄名   
  51.             printf("%s/t/t",FindFileData.cFileName);  
  52.             //判斷文件屬性,加密文件或文件夾   
  53.             if(FindFileData.dwFileAttributes&FILE_ATTRIBUTE_ENCRYPTED)  
  54.             {  
  55.                 printf("<加密> ");  
  56.             }  
  57.             //判斷文件屬性,隱藏文件或文件夾   
  58.             if(FindFileData.dwFileAttributes&FILE_ATTRIBUTE_HIDDEN)  
  59.             {  
  60.                 printf("<隱藏> ");  
  61.             }  
  62.             //判斷文件屬性,目錄   
  63.             if(FindFileData.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)  
  64.             {  
  65.                 printf("<DIR> ");  
  66.             }  
  67.             //讀者可根據文件屬性表中的內容自行添加判斷文件屬性。   
  68.             printf("/n");  
  69.         }  
  70.         while(FindNextFile(hListFile, &FindFileData));  
  71.     }  
  72.     return 0;  
  73. }  
  74.   
  75. /* ************************************ 
  76. * int main(int argc, PCHAR argv[]) 
  77. * 功能    調用ListFileInDrectory 
  78. *       遍歷目錄下的文件和子目錄 
  79. * 參數    argv[1]爲需遍歷的路徑,若是爲空則獲取 
  80. *       當前路徑 
  81. **************************************/  
  82. int main(int argc, PCHAR argv[])  
  83. {     
  84.     if(argc == 2)  
  85.     {  
  86.         EnumerateFileInDrectory(argv[1]);  
  87.     }  
  88.     else   
  89.     {  
  90.         CHAR szCurrentPath[MAX_PATH];  
  91.         GetCurrentDirectory(MAX_PATH,szCurrentPath);  
  92.         EnumerateFileInDrectory(szCurrentPath);  
  93.     }  
  94.     return 0;  
  95. }  

 



 4.3.6 遞歸遍歷目錄樹

 

在實例4-10的基礎上稍加改造,進行循環遞歸調用,採用樹形結構深度遍歷的方法。能夠遍歷指定目錄中的全部文件、包括子目錄中的文件。代碼實現如實例4-11所示。

  1. /* ************************************ 
  2. *《精通Windows API》  
  3. * 示例代碼 
  4. * tree.c 
  5. * 4.3.6 遞歸遍歷目錄樹 
  6. * 2007年10月 
  7. **************************************/  
  8.   
  9. /* 頭文件 */  
  10. #include <windows.h>   
  11. #include <stdio.h>   
  12.   
  13. /* 預處理申明 */  
  14. #pragma comment (lib, "User32.lib")   
  15.   
  16. /* 函數申明 */  
  17. DWORD ListAllFileInDrectory(LPSTR szPath);  
  18.   
  19. /* 全局變量 */  
  20. //記錄全部的文件和目錄數   
  21. DWORD dwTotalFileNum = 0;  
  22.   
  23.   
  24. /* ************************************ 
  25. * DWORD ListAllFileInDrectory(LPSTR szPath) 
  26. * 功能    遍歷目錄及全部子目錄,打印路徑 
  27. * 
  28. * 參數    LPTSTR szPath,爲需遍歷的目錄 
  29. * 
  30. * 返回值   0表明執行完成,1代碼發生錯誤 
  31. **************************************/  
  32. DWORD ListAllFileInDrectory(LPSTR szPath)  
  33. {  
  34.     CHAR szFilePath[MAX_PATH];  
  35.   
  36.     WIN32_FIND_DATA FindFileData;  
  37.     HANDLE hListFile;  
  38.     CHAR szFullPath[MAX_PATH];  
  39.   
  40.     //構造表明子目錄和文件夾路徑的字符串,使用通配符「*」   
  41.     lstrcpy(szFilePath, szPath);  
  42.     lstrcat(szFilePath, "//*");  
  43.     //查找第一個文件/目錄,得到查找句柄   
  44.     hListFile = FindFirstFile(szFilePath,&FindFileData);  
  45.   
  46.     if(hListFile==INVALID_HANDLE_VALUE)  
  47.     {  
  48.         printf("錯誤:%d",GetLastError());  
  49.         return 1;  
  50.     }  
  51.     else  
  52.     {         
  53.         do  
  54.         {  
  55.             //  過濾「.」和「..」,不須要遍歷   
  56.             if(lstrcmp(FindFileData.cFileName,TEXT("."))==0||  
  57.                 lstrcmp(FindFileData.cFileName,TEXT(".."))==0)  
  58.             {  
  59.                 continue;  
  60.             }  
  61.             //構形成全路徑   
  62.             wsprintf(szFullPath,"%s//%s",  
  63.                 szPath,FindFileData.cFileName);  
  64.             dwTotalFileNum++;  
  65.             //打印   
  66.             printf("/n%d/t%s/t",dwTotalFileNum,szFullPath);  
  67.   
  68.             //若是是目錄,則遞歸調用,列舉下級目錄   
  69.             if(FindFileData.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)  
  70.             {  
  71.                 printf("<DIR>");  
  72.                 ListAllFileInDrectory(szFullPath);  
  73.             }             
  74.         }  
  75.         while(FindNextFile(hListFile, &FindFileData));  
  76.     }  
  77.     return 0;  
  78. }  
  79.   
  80.   
  81. /* ************************************  
  82. int main(int argc, PCHAR argv[])  
  83. * 功能    調用ListAllFileInDrectory  
  84. *       遍歷目錄下的文件和子目錄  
  85. *  
  86. * 參數    argv[1]爲需遍歷的路徑,若是爲空則獲取  
  87. *       當前路徑  
  88. *  
  89. * 2007年10月  
  90. *  
  91. **************************************/  
  92. int main(int argc, PCHAR argv[])  
  93. {     
  94.     if(argc == 2)  
  95.     {  
  96.         ListAllFileInDrectory(argv[1]);  
  97.     }  
  98.     else   
  99.     {  
  100.         CHAR szCurrentPath[MAX_PATH];  
  101.         GetCurrentDirectory(MAX_PATH,szCurrentPath);  
  102.         ListAllFileInDrectory(szCurrentPath);  
  103.     }  
  104.     return 0;  
  105. }  

 

 



 

4.3.7 獲取、設置文件屬性和時間


爲了獲取文件屬性,用戶可使用GetFileAttributes與GetFileAttributesEx函數。
GetFileAttributesEx函數除了返回文件屬性外,還返回文件時間信息、文件大小等。
GetFileAttributesEx將返回結果保存在WIN32_FILE_ATTRIBUTE DATA結構中。
獲取的文件時間是以FILETIME格式存在的,若是要正確顯示,還須要對其時區進行調整,調整爲本地時區,而後轉換爲系統時間格式,便於顯示。
前面在獲取文件大小時已經介紹,NTFS文件系統使用了64位數據來表示文件大小。由於32位的數據最多隻能表示4GB的大小。Windows將其分爲了高32位和低32位,兩個都須要使用到,這一點尤爲要在對大於4GB的文件操做時注意。
1.關鍵API
(1)GetFileAttributeS。
獲取文件或目錄的屬牲-函數原型以下:

(2)GetFileAttributesEx。
獲取文件或目錄的屬性、時間、大小,以WIN32_FILE ATTRIBUTE_DATA結構的形式返回
結果,函數原型以下:

(3) SetFileAttributes.
設置文件或目錄的屬性,函數原型以下:

(4)FileTimeToLocalFileTime。
把文件時間轉換爲本地的文件時間,函數原型以下:

5)FileTimeToSystemTime
將文件時間轉換爲系統時間(SYSTEMTIME格式),便於顯示,函數原型以下:

2.關鍵數據結構
(1) FILETIM。
此結構用最小的數據量表示的時間,可是不便於用戶查看和顯示。經過API獲取的系統時間都是這種格式的。若是要使用顯示,可使用FileTimeToSystemTime轉換爲便於顯示的SYSTEMTIME結構。

(2) SYSTEMTIME。
此結構使用了較爲直觀的方式表示時間。

(3) WIN32_FILE ATTRIBUTE_DATA。
GetFileAttributesEx使用這個結構表示返回結果,包括文件屬性、文件建立時間、文件最後訪問時間、文件最後寫入時間和文件大小。

  1. /* ************************************ 
  2.  *《精通Windows API》  
  3.  * 示例代碼 
  4.  * attr.c 
  5.  * 4.3.7  獲取、設置文件屬性和時間 
  6.  **************************************/  
  7.   
  8. /* 頭文件 */  
  • #include <windows.h>   
  • #include <stdio.h>   
  •   
  • /* 函數申明 */  
  • DWORD ShowFileTime(PFILETIME lptime);  
  • DWORD ShowFileSize(DWORD dwFileSizeHigh,DWORD dwFileSizeLow);  
  • DWORD ShowFileAttrInfo(DWORD dwAttribute);  
  • DWORD SetFileHiddenAndReadonly(LPSTR szFileName);  
  •   
  • /* ************************************ 
  •  * DWORD ShowFileAttributes(LPSTR szPath) 
  •  * 功能   獲取並顯示文件屬性, 
  •  *      調用ShowFileTime、ShowFileSize和 
  •  *      ShowFileAttrInfo函數 
  •  * 
  •  * 參數   LPTSTR szPath,獲取並顯示此文件的屬性 
  •  * 
  •  * 返回值  0表明執行完成,1代碼發生錯誤 
  •  **************************************/  
  • DWORD ShowFileAttributes(LPSTR szPath)  
  • {  
  •     //文件屬性結構   
  •     WIN32_FILE_ATTRIBUTE_DATA wfad;  
  •     printf("文件:%s/n",szPath);  
  •     //獲取文件屬性   
  •     if(!GetFileAttributesEx(szPath,  
  •         GetFileExInfoStandard,  
  •         &wfad))  
  •     {  
  •         printf("獲取文件屬性錯誤:%d/n",GetLastError());  
  •         return 1;  
  •     }  
  •     //顯示相關時間   
  •     printf("建立時間:/t");  
  •     ShowFileTime(&(wfad.ftCreationTime));  
  •     printf("最後訪問時間:/t");  
  •     ShowFileTime(&(wfad.ftLastAccessTime));  
  •     printf("最後修改時間:/t");  
  •     ShowFileTime(&(wfad.ftLastWriteTime));  
  •     //顯示文件大小   
  •     ShowFileSize(wfad.nFileSizeHigh,wfad.nFileSizeLow);  
  •     //顯示文件屬性   
  •     ShowFileAttrInfo(wfad.dwFileAttributes);  
  •   
  •     return 0;  
  • }  
  •   
  • /* ************************************ 
  •  * DWORD ShowFileAttrInfo(DWORD dwAttribute) 
  •  * 功能   打印將文件屬性 
  •  * 
  •  * 參數   DWORD dwAttribute,文件屬性 
  •  * 
  •  * 返回值 0 
  •  **************************************/  
  • DWORD ShowFileAttrInfo(DWORD dwAttribute)  
  • {  
  •     //依次判斷屬性,並顯示。   
  •     printf("文件屬性:/t");  
  •     if(dwAttribute&FILE_ATTRIBUTE_ARCHIVE)  
  •         printf("<ARCHIVE> ");  
  •     if(dwAttribute&FILE_ATTRIBUTE_COMPRESSED)  
  •         printf("<壓縮> ");  
  •     if(dwAttribute&FILE_ATTRIBUTE_DIRECTORY)  
  •         printf("<目錄> ");  
  •     if(dwAttribute&FILE_ATTRIBUTE_ENCRYPTED)  
  •         printf("<加密> ");  
  •     if(dwAttribute&FILE_ATTRIBUTE_HIDDEN)  
  •         printf("<隱藏> ");  
  •     if(dwAttribute&FILE_ATTRIBUTE_NORMAL)  
  •         printf("<NORMAL> ");  
  •     if(dwAttribute&FILE_ATTRIBUTE_OFFLINE)  
  •         printf("<OFFLINE> ");  
  •     if(dwAttribute&FILE_ATTRIBUTE_READONLY)  
  •         printf("<只讀> ");  
  •     if(dwAttribute&FILE_ATTRIBUTE_SPARSE_FILE)  
  •         printf("<SPARSE> ");  
  •     if(dwAttribute&FILE_ATTRIBUTE_SYSTEM)  
  •         printf("<系統文件> ");  
  •     if(dwAttribute&FILE_ATTRIBUTE_TEMPORARY)  
  •         printf("<臨時文件> ");  
  •   
  •     printf("/n");  
  •   
  •     return 0;  
  • }  
  • /* ************************************ 
  •  * DWORD ShowFileSize(DWORD dwFileSizeHigh, DWORD dwFileSizeLow) 
  •  * 功能   打印文件大小信息 
  •  * 
  •  * 參數   DWORD dwFileSizeHigh,文件大小高32位 
  •  *      DWORD dwFileSizeLow,文件大小低32位 
  •  * 
  •  * 返回值 0 
  •  **************************************/  
  • DWORD ShowFileSize(DWORD dwFileSizeHigh, DWORD dwFileSizeLow)  
  • {  
  •     ULONGLONG liFileSize;  
  •     liFileSize = dwFileSizeHigh;  
  •   
  •     //高們移動32位   
  •     liFileSize <<= sizeof(DWORD)*8;  
  •     liFileSize += dwFileSizeLow;  
  •     printf("文件大小:/t%I64u 字節/n",liFileSize);  
  •     return 0;  
  • }  
  •   
  • /* ************************************ 
  •  *DWORD ShowFileTime(PFILETIME lptime) 
  •  * 功能   輪換文件時間,將打印 
  •  * 
  •  * 參數   PFILETIME lptime,指向文件時間的指針 
  •  * 
  •  * 返回值 0 
  •  **************************************/  
  • DWORD ShowFileTime(PFILETIME lptime)  
  • {  
  •     //文件時間結構   
  •     FILETIME ftLocal;  
  •     //系統時間結構   
  •     SYSTEMTIME st;  
  •     //調整爲系統所在時區的時間   
  •     FileTimeToLocalFileTime(  
  •         lptime,  
  •         &ftLocal  
  •         );  
  •     //將文件時間轉換爲SYSTEMTIME格式,便於顯示。   
  •     FileTimeToSystemTime(  
  •         &ftLocal,  
  •         &st  
  •         );  
  •     //顯示時間信息字符串   
  •     printf("%4d年%.2d月%#02d日,%.2d:%.2d:%.2d/n",  
  •         st.wYear,st.wMonth,st.wDay,st.wHour,st.wMinute,st.wSecond);  
  •   
  •     return 0;  
  • }  
  •   
  • /* ************************************ 
  •  * DWORD SetFileHiddenAndReadonly(LPSTR szFileName) 
  •  * 功能   將指定的文件設置爲隱藏和只讀 
  •  * 
  •  * 參數   LPSTR szFileName,文件路徑 
  •  * 
  •  * 返回值 0 
  •  **************************************/  
  • DWORD SetFileHiddenAndReadonly(LPSTR szFileName)  
  • {  
  •     //獲取原來的文件屬性   
  •     DWORD dwFileAttributes = GetFileAttributes(szFileName);  
  •     //將只讀和隱藏屬性附加到原來的文件屬性上   
  •     dwFileAttributes |= FILE_ATTRIBUTE_READONLY;  
  •     dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;  
  •     //設置文件屬性,並判斷是否成功。   
  •     if(SetFileAttributes(szFileName, dwFileAttributes))  
  •     {  
  •         printf("文件%s的隱藏和屬性設置成功/n",szFileName);  
  •     }  
  •     else  
  •     {  
  •         printf("屬性設置; %d/n",GetLastError());  
  •     }  
  •     return 0;  
  • }  
  •   
  • /* ************************************ 
  •  * int main(int argc, PCHAR argv[]) 
  •  * 功能   設置和獲取文件屬性等 
  •  * 
  •  * 參數   顯示第一個參數指定文件的屬性、時間、大小 
  •  *      將第二個參數的屬性設置爲隱藏、只讀。 
  •  * 
  •  * 返回值  0表明執行完成,1代碼發生錯誤 
  •  **************************************/  
  • int main(int argc, PCHAR argv[])  
  • {     
  •     if(argc != 3)  
  •     {  
  •         printf("請輸入參數/n");  
  •         printf("顯示第一個參數指定文件的屬性、時間、大小;/n");  
  •         printf("將第二個參數的屬性設置爲隱藏、只讀。");  
  •         return 1;  
  •     }  
  •     ShowFileAttributes(argv[1]);  
  •     SetFileHiddenAndReadonly(argv[2]);  
  •     return 0;  
  • }  

 

 


 

 

 

 


 

 

 

 4.4 內存映射文件


本節介紹Mapping File、文件句柄等較高級操做。本節將經過如下幾個實例來說解高級文件系統操做的API。
◇ 使用Mapping File提升文件讀寫的效率。
◇經過Mapping File在進程間共享內存。
◇經過文件句柄得到文件路徑。
4.4.1 使用Mapping File提升文件讀寫的效率
文件映射( mapping)是一種在將文件內容映射到進程的虛擬地址空間的技術。視圖(View)是一段虛擬地址空間,進程能夠經過View來存取文件的內容,視圖是一段內存,可使用指針來操做視圖。使用的文件映射以後,讀寫文件就如同對讀寫內存同樣簡單。在使用文件映射時須要建立映射對象,映射對象分爲命名的和未命名的。映射對象還存取權限。
使用文件映射至少有3個好處,一是由於文件是存儲於硬盤上的,而文件視圖是一段內存,使用文件映射操做時更方便;二是效率更高;三是能夠在不一樣的進程間共享數據。
文件映射依賴於系統虛擬內存管理的分頁機制。
本節將演示如何使用文件映射,下一節將演示如何使用文件映射來進行內存共享。
1. 關鍵API
(1)GetSystemInfo
獲取系統信息,在實例 4-14中用於獲取系統內存分配粒度。有關內存分配粒度的概念參見第5章和虛擬內存管理相關章節。
(2)CreateFileMapping。
建立mapping對象,函數原型以下

(3)MapViewOfFile。
建立視圖,將文件mapping映射到當前進程內存虛擬地址空間。函數原型以下:

 (4)FlushViewOfFile。
將視圖中的文件數據寫入到磁盤上。調用此參數後,對映射視圖的內存操做將會及時反映到硬件中的文件。函數原型以下:

◇使用說明
若是不調用此函數,數據最終也會寫回到硬盤,調用此函數後,數據會馬上寫回到硬盤。
(5) FillMemory、CopyMemory。內存操做函數,分別爲填充內存和複製內存,詳見第5章

 

  1. /* ************************************ 
  2. *《精通Windows API》  
  3. * 示例代碼 
  4. * file_map.c 
  5. * 4.4.1  使用Mapping File提升文件讀寫的效率 
  6. **************************************/  
  7.   
  8. /* 頭文件 */  
  9. #include <windows.h>   
  10. #include <stdio.h>   
  11. /* 預處理申明 */  
  12. #define BUFFSIZE 1024                   // 內存大小   
  13. #define FILE_MAP_START 0x28804          // 文件映射的起始的位置   
  14. /* 全局變量 */  
  15. LPTSTR lpcTheFile = TEXT("test.dat");   // 文件名   
  16.   
  17. /* ************************************ 
  18. * int main(void) 
  19. * 功能    演示使用文件mapping 
  20. * 
  21. * 參數    無 
  22. * 
  23. * 返回值   0表明執行完成,1表明發生錯誤 
  24. **************************************/  
  25. int main(void)  
  26. {  
  27.     HANDLE hMapFile;      // 文件內存映射區域的句柄   
  28.     HANDLE hFile;         // 文件的句柄   
  29.     DWORD dBytesWritten;  // 寫入的字節數   
  30.     DWORD dwFileSize;     // 文件大小   
  31.     DWORD dwFileMapSize;  // 文件映射的大小   
  32.     DWORD dwMapViewSize;  // 視圖(View)的大小   
  33.     DWORD dwFileMapStart; // 文件映射視圖的起始位置   
  34.     DWORD dwSysGran;      // 系統內存分配的粒度   
  35.     SYSTEM_INFO SysInfo;  // 系統信息   
  36.     LPVOID lpMapAddress;  // 內在映射區域的起始位置   
  37.     PCHAR pData;            // 數據   
  38.     INT i;                // 循環變量   
  39.     INT iData;  
  40.     INT iViewDelta;  
  41.     BYTE cMapBuffer[32];  // 存儲從mapping中計出的數據   
  42.   
  43.     // 建立一個文件   
  44.     hFile = CreateFile(lpcTheFile,   
  45.         GENERIC_READ | GENERIC_WRITE,  
  46.         0,   
  47.         NULL,  
  48.         CREATE_ALWAYS,   
  49.         FILE_ATTRIBUTE_NORMAL,   
  50.         NULL);  
  51.     //判斷文件是否建立成功   
  52.     if (hFile == INVALID_HANDLE_VALUE)  
  53.     {  
  54.         printf("CreateFile error/n",GetLastError);  
  55.         return 1;  
  56.     }  
  57.     // 依次寫入整數,一共寫入65535個整數   
  58.     // 在32位平臺下,大小爲65535*32   
  59.     for (i=0; i<65535; i++)   
  60.     {  
  61.         WriteFile (hFile, &i, sizeof (i), &dBytesWritten, NULL);  
  62.     }  
  63.     // 查看寫入完成後的文件大小   
  64.     dwFileSize = GetFileSize(hFile,  NULL);  
  65.     printf("文件大小: %d/n", dwFileSize);  
  66.   
  67.     //獲取系統信息,內存分配粒度   
  68.     //獲取分配粒度,進行下面的幾個計算,   
  69.     //目的是爲了映射的數據與系統內存分配粒度對齊,提升內存訪問效率   
  70.     GetSystemInfo(&SysInfo);  
  71.     dwSysGran = SysInfo.dwAllocationGranularity;  
  72.   
  73.     //計算mapping的起始位置   
  74.     dwFileMapStart = (FILE_MAP_START / dwSysGran) * dwSysGran;  
  75.     // 計算mapping view的大小   
  76.     dwMapViewSize = (FILE_MAP_START % dwSysGran) + BUFFSIZE;  
  77.     // 計算mapping的大小   
  78.     dwFileMapSize = FILE_MAP_START + BUFFSIZE;  
  79.     // 計算須要讀取的數據的偏移   
  80.     iViewDelta = FILE_MAP_START - dwFileMapStart;  
  81.   
  82.     // 建立File mapping   
  83.     hMapFile = CreateFileMapping( hFile,          // 須要映射的文件的句柄   
  84.         NULL,           // 安全選項:默認   
  85.         PAGE_READWRITE, // 可讀,可寫   
  86.         0,              // mapping對象的大小,高位   
  87.         dwFileMapSize,  // mapping對象的大小,低位   
  88.         NULL);          // mapping對象的名字   
  89.     if (hMapFile == NULL)   
  90.     {  
  91.         printf("CreateFileMapping error: %d/n", GetLastError() );  
  92.         return 1;  
  93.     }  
  94.   
  95.     // 映射view   
  96.     lpMapAddress = MapViewOfFile(hMapFile,            // mapping對象的句柄   
  97.         FILE_MAP_ALL_ACCESS, // 可讀,可寫   
  98.         0,                   // 映射的文件偏移,高32位   
  99.         dwFileMapStart,      // 映射的文件偏移,低32位   
  100.         dwMapViewSize);      // 映射到View的數據大小   
  101.     if (lpMapAddress == NULL)   
  102.     {  
  103.         printf("MapViewOfFile error: %d/n", GetLastError());  
  104.         return 1;  
  105.     }  
  106.   
  107.     printf ("文件map view相對於文件的起始位置: 0x%x/n",  
  108.         dwFileMapStart);  
  109.     printf ("文件map view的大小:0x%x/n",     dwMapViewSize);  
  110.     printf ("文件mapping對象的大小:0x%x/n", dwFileMapSize);  
  111.     printf ("從相對於map view 0x%x 字節的位置讀取數據,", iViewDelta);  
  112.   
  113.     // 將指向數據的指針偏移,到達咱們關心的地方   
  114.     pData = (PCHAR) lpMapAddress + iViewDelta;  
  115.     // 讀取數據,賦值給變量   
  116.     iData = *(PINT)pData;  
  117.     // 顯示讀取的數據   
  118.     printf ("爲:0x%.8x/n", iData);  
  119.   
  120.     // 從mapping中複製數據,32個字節,並打印   
  121.     CopyMemory(cMapBuffer,lpMapAddress,32);  
  122.     printf("lpMapAddress起始的32字節是:");  
  123.     for(i=0; i<32; i++)  
  124.     {  
  125.         printf("0x%.2x ",cMapBuffer[i]);  
  126.     }  
  127.     // 將mapping的前32個字節用0xff填充   
  128.     FillMemory(lpMapAddress,32,(BYTE)0xff);  
  129.     // 將映射的數據寫回到硬盤上   
  130.     FlushViewOfFile(lpMapAddress,dwMapViewSize);  
  131.     printf("/n已經將lpMapAddress開始的32字節使用0xff填充。/n");  
  132.   
  133.     // 關閉mapping對象   
  134.     if(!CloseHandle(hMapFile))   
  135.     {  
  136.         printf("/nclosing the mapping object error %d!",  
  137.             GetLastError());  
  138.     }  
  139.     //關閉文件   
  140.     if(!CloseHandle(hFile))   
  141.     {  
  142.         printf("/nError %ld occurred closing the file!",  
  143.             GetLastError());  
  144.     }  
  145.   
  146.     return 0;  
  147. }  

 




4.4.2 經過Mapping File在進程間傳遞和共享數據
進程間通訊、共享數據有不少種方法,文件映射是經常使用的一種方法。由於mapping對象
系統中是全局的,一個進程建立的Mapping對象能夠從另一個進程中打開,映射視圖就
進程間共享的內存了。通常在共享的內存數據量比較大時,選擇使用文件映射進行共享。
1.關鍵API
(1)OpenFileMapping。
打開已經存在的文件映射,函數原型以下:

(2) UnmapViewO伍ile。
取消文件映射,函數原型以下:

  1. /* ************************************ 
  2. *《精通Windows API》 
  3. * 示例代碼 
  4. * pro_s1.c 
  5. * 4.4.2  經過Mapping File在進程間共享內存 
  6. **************************************/  
  7. /* 頭文件 */  
  8. #include <windows.h>   
  9. #include <stdio.h>   
  10. #include <conio.h>   
  11. /* 預處理申明 */  
  12. #define BUF_SIZE 256   
  13. /* 全局變量 */  
  14. LPTSTR szName = TEXT("SharedFileMappingObject");  
  15. LPTSTR szMsg = TEXT("進程的消息");  
  16.   
  17. /* ************************************ 
  18. * int main(void) 
  19. * 功能    演示文件mapping共享內存,寫入數據到共享內存 
  20. * 
  21. * 參數    無 
  22. * 
  23. * 返回值   0表明執行完成,表明發生錯誤 
  24. **************************************/  
  25. void main(int argc, PCHAR argv[])  
  26. {  
  27.     //文件映射句柄   
  28.     HANDLE hMapFile;  
  29.     //共享數據緩衝區指針   
  30.     LPTSTR pBuf;  
  31.     //建立命名的文件映射,不表明任務硬盤上的文件   
  32.     hMapFile = CreateFileMapping(  
  33.         INVALID_HANDLE_VALUE,  
  34.         NULL,   
  35.         PAGE_READWRITE,  
  36.         0,  
  37.         BUF_SIZE,   
  38.         szName);  
  39.     if (hMapFile == NULL || hMapFile == INVALID_HANDLE_VALUE)   
  40.     {   
  41.         printf("CreateFileMapping error: %d/n", GetLastError());  
  42.         return;  
  43.     }  
  44.     //建立View   
  45.     pBuf = (LPTSTR) MapViewOfFile(hMapFile,  
  46.         FILE_MAP_ALL_ACCESS,  
  47.         0,                     
  48.         0,                     
  49.         BUF_SIZE);  
  50.     if (pBuf == NULL)   
  51.     {   
  52.         printf("MapViewOfFile error %d/n",  GetLastError());   
  53.         return;  
  54.     }  
  55.     //將共享數據複製到文件映射中,若是運行時輸入了參數則使用參數   
  56.     if(argc==1)  
  57.     {  
  58.         CopyMemory((PVOID)pBuf, szMsg, strlen(szMsg));  
  59.     }  
  60.     else  
  61.     {  
  62.         DWORD dwCopyLen = (lstrlen(argv[1])<BUF_SIZE) ? lstrlen(argv[1]): BUF_SIZE;  
  63.         CopyMemory((PVOID)pBuf, argv[1], dwCopyLen);  
  64.     }  
  65.     printf("運行程序,完成運行後,按任意鍵退出。");  
  66.     _getch();  
  67.     //取消映射,退出   
  68.     UnmapViewOfFile(pBuf);  
  69.     CloseHandle(hMapFile);  
  70. }  

 



.實例4-15讀取並顯示共享數據
本實例代碼從實例4-14共享的Mapping對象中讀取數據,並將數據顯示出來。實例4-14與實例4-15是兩個進程,實現了進程間數據的共享。這兩個進程能夠經過各自的指針,對同一段內存進行讀寫。
本實例先打開指定對象名的Mapping對象(與實例4-14中使用的CreateFileMapping建立的Mapping對象需有同樣的對象名),而後建立視圖,從視圖中讀取數據。

  1. /* ************************************ 
  2. *《精通Windows API》 
  3. * 示例代碼 
  4. * pro_s2.c 
  5. * 4.4.2  經過Mapping File在進程間共享內存 
  6. **************************************/  
  7. #include <windows.h>   
  8. #include <stdio.h>   
  9. #include <conio.h>   
  10. /* 預處理申明*/  
  11. #pragma comment (lib, "User32.lib")   
  12. #define BUF_SIZE 256   
  13. /* 全局變量 */  
  14. TCHAR szName[]=TEXT("SharedFileMappingObject");  
  15.   
  16. /* ************************************ 
  17. * int main(void) 
  18. * 功能    演示文件mapping共享內存,從共享數據中讀信息 
  19. * 
  20. * 參數    無 
  21. * 
  22. * 返回值   0表明執行完成,表明發生錯誤 
  23. **************************************/  
  24. void main()  
  25. {  
  26.     HANDLE hMapFile;  
  27.     LPTSTR pBuf;  
  28.     //打開文件mapping   
  29.     hMapFile = OpenFileMapping(  
  30.         FILE_MAP_ALL_ACCESS,  
  31.         FALSE,  
  32.         szName);   
  33.     if (hMapFile == NULL)   
  34.     {   
  35.         printf("OpenFileMapping error: %d./n",  GetLastError());  
  36.         return;  
  37.     }   
  38.     //映射   
  39.     pBuf = MapViewOfFile(hMapFile,  
  40.         FILE_MAP_ALL_ACCESS,  
  41.         0,                      
  42.         0,                      
  43.         BUF_SIZE);    
  44.     if (pBuf == NULL)   
  45.     {   
  46.         printf("MapViewOfFile error %d/n", GetLastError());   
  47.         return;  
  48.     }  
  49.     //消息獲得的共享數據   
  50.     MessageBox(NULL, pBuf, TEXT("Process2"), MB_OK);  
  51.     //取消mapping,關閉句柄,返回   
  52.     UnmapViewOfFile(pBuf);  
  53.     CloseHandle(hMapFile);  
  54. }  

 

 


 

 


 

4.4.3 經過文件句柄得到文件路徑
Windows系統提供了一個名爲GetMappedFileName的API函數,這個函數能夠實現從
mapping對象的句柄獲得被映射文件的路徑。可是路徑是以設備名的形式給出的,如相似於
「/Device/HarddiskVolume3/1.TXT」的形式。
將設備名轉換爲路徑名須要使用到一個API函數-QueryDosDevice,這個函數能夠將驅動器的根路徑轉換爲設備名,而後進行循環比較,可得文件路徑。
1.關鍵API
(1)GetMappedFileName。
從映射對象獲取被映射文件的文件設備名,函數原型以下:

(2)QueryDosDevice
獲取MS_DOS設備名,函數原型以下:

◇返回值返回DWORD值,若是成功,則返回值爲lpTargetPath指向字符串的長度,若是失敗爲0。
2.實例4-16經過文件句柄獲取文件路徑
GetFileNameFromHandle經過參數輸入的句柄建立mapping對象,而後調用GetMapped
FileName函數,得到對象所映射的文件的設備名,而後使用QueryDosDevice函數循環判斷
驅動器設備名與路徑的關係,在找到正確的驅動器路徑後,構造好文件路徑並輸出。

  1. /* ************************************ 
  2. *《精通Windows API》 
  3. * 示例代碼 
  4. * handle_path.cpp 
  5. * 4.4.3 經過文件句柄獲取文件路徑 
  6. **************************************/  
  7. /* 頭文件*/  
  8. #include <windows.h>   
  9. #include <stdio.h>   
  10. #include <tchar.h>   
  11. #include <string.h>   
  12. #include <psapi.h>   
  13. /* 預處理申明*/  
  14. #pragma comment (lib, "Psapi.lib")   
  15. #define BUFSIZE 512   
  16. /* 函數申明*/  
  17. BOOL GetFileNameFromHandle(HANDLE hFile) ;  
  18.   
  19. /* ************************************ 
  20. * BOOL GetFileNameFromHandle(HANDLE hFile)  
  21. * 功能    從文件句柄獲取文件路徑 
  22. * 
  23. * 參數    ANDLE hFile,須要得到路徑的文件句柄 
  24. * 
  25. * 返回值BOOL 是否成功。 
  26. **************************************/  
  27. BOOL GetFileNameFromHandle(HANDLE hFile)   
  28. {  
  29.     TCHAR pszFilename[MAX_PATH+1];  
  30.     HANDLE hFileMap;  
  31.     PVOID pMem;  
  32.   
  33.     // 得到文件大小,並決斷是否爲   
  34.     DWORD dwFileSizeHigh = 0;  
  35.     DWORD dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh);   
  36.     if( dwFileSizeLow == 0 && dwFileSizeHigh == 0 )  
  37.     {  
  38.         printf("不能map文件大小爲的文件./n");  
  39.         return FALSE;  
  40.     }  
  41.     // 建立mapping對象   
  42.     hFileMap = CreateFileMapping(hFile,   
  43.         NULL,   
  44.         PAGE_READONLY,  
  45.         0,   
  46.         1,  
  47.         NULL);  
  48.     if (!hFileMap)   
  49.     {  
  50.         printf("CreateFileMapping error: %d",GetLastError());  
  51.         return FALSE;  
  52.     }  
  53.   
  54.     pMem = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 1);  
  55.     if (!pMem)   
  56.     {  
  57.         printf("MapViewOfFile error: %d",GetLastError());  
  58.         return FALSE;  
  59.     }  
  60.     // 從mapping對象得到文件名   
  61.     if (0 == GetMappedFileName (GetCurrentProcess(),   
  62.         pMem,   
  63.         pszFilename,  
  64.         MAX_PATH))  
  65.     {  
  66.         printf("GetMappedFileName error: %d",GetLastError());  
  67.         return FALSE;  
  68.     }  
  69.     // 將設備名轉換爲路徑   
  70.     TCHAR szTemp[BUFSIZE] = {0};  
  71.     if (0 == GetLogicalDriveStrings(BUFSIZE-1, szTemp))   
  72.     {  
  73.         printf("GetLogicalDriveStrings error: %d",GetLastError());  
  74.         return FALSE;  
  75.     }  
  76.     TCHAR szName[MAX_PATH];  
  77.     TCHAR szDrive[3] = {0};  
  78.     BOOL bFound = FALSE;  
  79.     PTCHAR p = szTemp;  
  80.     do   
  81.     {  
  82.         CopyMemory(szDrive,p,2*sizeof(TCHAR));  
  83.         // 經過路徑查找設備名   
  84.         if (!QueryDosDevice(szDrive, szName, BUFSIZE))  
  85.         {  
  86.             printf("QueryDosDevice error: %d",GetLastError());  
  87.             return FALSE;  
  88.         }  
  89.         UINT uNameLen = lstrlen(szName);  
  90.         if (uNameLen < MAX_PATH)   
  91.         {  
  92.             //比較驅動器的設備名與文件設備名是否匹配   
  93.             bFound = strncmp(pszFilename, szName,uNameLen) == 0;  
  94.             if (bFound)   
  95.             {  
  96.                 //若是匹配,說明已經找到,構造路徑。   
  97.                 TCHAR szTempFile[MAX_PATH];  
  98.                 wsprintf(szTempFile,  
  99.                     TEXT("%s%s"),  
  100.                     szDrive,  
  101.                     pszFilename+uNameLen);  
  102.                 lstrcpy(pszFilename, szTempFile);  
  103.             }  
  104.         }  
  105.         // 循環到下一個NULL   
  106.         while (*p++);  
  107.     } while (!bFound && *p);  
  108.   
  109.     UnmapViewOfFile(pMem);  
  110.     CloseHandle(hFileMap);  
  111.     printf("File path is %s/n", pszFilename);  
  112.     return TRUE;  
  113. }  
  114.   
  115. /* ************************************ 
  116. * int main() 
  117. * 功能    查找第一個目錄中第一個txt文件 
  118. *       打開文件,並根據文件句柄得到文件路徑。 
  119. * 
  120. * 參數    未使用 
  121. * 
  122. * 返回值0表示成功,表示失敗。 
  123. **************************************/  
  124. int main()  
  125. {  
  126.     HANDLE hFile;  
  127.     HANDLE hFind;  
  128.     WIN32_FIND_DATA wfd;  
  129.     hFind = FindFirstFile("*.txt",&wfd);  
  130.     if(hFind == INVALID_HANDLE_VALUE)  
  131.     {  
  132.         printf("can not find a file");  
  133.         return 1;  
  134.     }  
  135.     //CloseHandle(hFind);   
  136.     printf("find %s at current dir/n",wfd.cFileName);  
  137.     hFile = CreateFile(wfd.cFileName,   
  138.         GENERIC_READ | GENERIC_WRITE,  
  139.         0,   
  140.         NULL,  
  141.         OPEN_EXISTING,   
  142.         FILE_ATTRIBUTE_NORMAL,   
  143.         NULL);  
  144.     if(hFile == INVALID_HANDLE_VALUE)  
  145.     {  
  146.         printf("create file error, %d",GetLastError());  
  147.     }  
  148.     else  
  149.     {  
  150.         GetFileNameFromHandle(hFile) ;  
  151.     }  
  152.     CloseHandle(hFile);  
  153.     return 0;  
  154. }  

相關文章
相關標籤/搜索