1. 程式人生 > >《精通Windows API-函式、介面、程式設計例項》——第4章檔案系統

《精通Windows API-函式、介面、程式設計例項》——第4章檔案系統

第4章檔案系統

4.2 磁碟和驅動器管理

檔案系統的基本概念: 包括磁碟分割槽,卷,目錄,檔案物件,檔案控制代碼,檔案對映 1.磁碟分割槽: 物理磁碟,邏輯磁碟 2.卷: 也稱邏輯驅動器,是NTFS,FAT32等檔案系統組織結構的最高層. 卷是儲存裝置(硬碟)上由檔案系統管理的一塊區域,在邏輯上相互隔離的儲存單元.

windows命名規則: 主檔名+副檔名 windows中檔案系統的長度被限制為260個字元. 這260個字元包括卷標,路徑,主檔名和副檔名,分隔符

在DOS下的保留裝置名不能做檔名或主檔名.如CON,PRN,AUX,NUL,COM1.....

=================================================================

磁碟和驅動器管理APIGetLogicalDrivers       獲取主機中所有的邏輯驅動器,以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格式便於顯示

高階檔案操作 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。 獲取邏輯驅動器資訊,其函式原型如下:

    

[cpp] view plaincopyprint?

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

 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 將指定卷掛載到指定掛載點處,函式原型如下:

[cpp] view plaincopyprint?

  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.  * ProcessVolumeMountPoint 
  16.  * 功能   列舉掛載點 
  17.  **************************************/  
  18. BOOL ProcessVolumeMountPoint (HANDLE hPt,  
  19.                               TCHAR *PtBuf, DWORD dwPtBufSize,  
  20.                               TCHAR *Buf)  
  21. {  
  22.     BOOL bFlag;                 // 結果   
  23.     TCHAR Path[BUFSIZE];    // 全路徑   
  24.     TCHAR Target[BUFSIZE];      // 掛載點裝置   
  25.     printf ("/tVolume mount point found is /"%s/"/n", PtBuf);  
  26.     lstrcpy (Path, Buf);  
  27.     lstrcat (Path, PtBuf);  
  28.     bFlag = GetVolumeNameForVolumeMountPoint(  
  29.         Path,  Target,  BUFSIZE     );  
  30.     if (!bFlag)  
  31.         printf ("/tAttempt to get volume name for %s failed./n", Path);  
  32.     else   
  33.         printf ("/tTarget of the volume mount point is %s./n", Target);  
  34.     bFlag = FindNextVolumeMountPoint(  
  35.         hPt,  PtBuf,  dwPtBufSize );  
  36.     return (bFlag);  
  37. }  
  38. /* ************************************ 
  39.  * ProcessVolume 
  40.  * 功能   判斷卷型別,列舉掛載點 
  41.  **************************************/  
  42. BOOL ProcessVolume (HANDLE hVol, TCHAR *Buf, DWORD iBufSize)  
  43. {  
  44.     BOOL bFlag;           // 返回標誌   
  45.     HANDLE hPt;           // 卷控制代碼   
  46.     TCHAR PtBuf[BUFSIZE]; // 掛載點路徑   
  47.     DWORD dwSysFlags;     // 檔案系統標記   
  48.     TCHAR FileSysNameBuf[FILESYSNAMEBUFSIZE];  
  49.     printf ("Volume found is /"%s/"./n", Buf);  
  50.     // 是否NTFS   
  51.     GetVolumeInformation( Buf, NULL, 0, NULL, NULL,  
  52.         &dwSysFlags, FileSysNameBuf,   
  53.         FILESYSNAMEBUFSIZE);  
  54.     if (! (dwSysFlags & FILE_SUPPORTS_REPARSE_POINTS))   
  55.     {  
  56.         printf ("/tThis file system does not support volume mount points./n");  
  57.     }   
  58.     else   
  59.     {  
  60.         // 本卷中的掛載點   
  61.         hPt = FindFirstVolumeMountPoint(  
  62.             Buf, // 卷的跟跟蹤   
  63.             PtBuf, // 掛載點路徑   
  64.             BUFSIZE   
  65.             );  
  66.         if (hPt == INVALID_HANDLE_VALUE)  
  67.         {  
  68.             printf ("/tNo volume mount points found!/n");  
  69.         }   
  70.         else   
  71.         {  
  72.             // 處理掛載點   
  73.             bFlag = ProcessVolumeMountPoint (hPt,   
  74.                 PtBuf,   
  75.                 BUFSIZE,   
  76.                 Buf);  
  77.             // 迴圈   
  78.             while (bFlag)   
  79.                 bFlag =   
  80.                 ProcessVolumeMountPoint (hPt, PtBuf, BUFSIZE, Buf);  
  81.             // 結束   
  82.             FindVolumeMountPointClose(hPt);  
  83.         }  
  84.     }  
  85.     // 下一個   
  86.     bFlag = FindNextVolume(  
  87.         hVol, Buf,  iBufSize);  
  88.     return (bFlag);   
  89. }  
  90. /* ************************************ 
  91.  * int GetMountPoint(void) 
  92.  * 功能   獲取掛載點 
  93.  **************************************/  
  94. int GetMountPoint(void)  
  95. {  
  96.     TCHAR buf[BUFSIZE];     // 卷識別符號   
  97.     HANDLE hVol;                    // 卷控制代碼   
  98.     BOOL bFlag;                 // 結果標誌   
  99.     printf("Volume mount points info of this computer:/n/n");  
  100.     // 打開卷   
  101.     hVol = FindFirstVolume (buf, BUFSIZE );  
  102.     if (hVol == INVALID_HANDLE_VALUE)  
  103.     {  
  104.         printf ("No volumes found!/n");  
  105.         return (-1);  
  106.     }  
  107.     bFlag = ProcessVolume (hVol, buf, BUFSIZE);  
  108.     while (bFlag)   
  109.     {  
  110.         bFlag = ProcessVolume (hVol, buf, BUFSIZE);  
  111.     }  
  112.     bFlag = FindVolumeClose(    hVol );  
  113.     return (bFlag);  
  114. }  
  115. /* ************************************ 
  116.  * void Usage (PCHAR argv) 
  117.  * 功能   使用方法 
  118.  **************************************/  
  119. void Usage (PCHAR argv)  
  120. {  
  121.     printf( "/n/n/t%s, mount a volume at a mount point./n", argv );  
  122.     printf( "/tFor example, /"mount D://mnt//drives// E:///"/n" );   
  123. }  
  124. /* ************************************ 
  125.  *  main 
  126.  * 功能   入口函式 
  127.  **************************************/  
  128. int main( int argc, PCHAR argv[] )  
  129. {  
  130.     BOOL bFlag;  
  131.     CHAR Buf[BUFSIZE];       
  132.     if( argc != 3 )   
  133.     {  
  134.         GetMountPoint();  
  135.         Usage( argv[0] );  
  136.         return( -1 );  
  137.     }  
  138.     bFlag = GetVolumeNameForVolumeMountPoint(  
  139.         argv[2],        // 輸入掛載點或目錄   
  140.         Buf,                // 輸出卷名   
  141.         BUFSIZE  
  142.         );  
  143.     if (bFlag != TRUE)   
  144.     {  
  145.         printf( "Retrieving volume name for %s failed./n", argv[2] );  
  146.         return (-2);  
  147.     }  
  148.     printf( "Volume name of %s is %s/n", argv[2], Buf );  
  149.     bFlag = SetVolumeMountPoint(  
  150.         argv[1],    // 掛載點   
  151.         Buf         // 需要掛載的卷   
  152.         );  
  153.     if (!bFlag)  
  154.     {  
  155.         printf ("Attempt to mount %s at %s failed. error code is/n",   
  156.             argv[2], argv[1], GetLastError());  
  157.     }  
  158.     return (bFlag);  
  159. }  

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函式原型如下:

[cpp] view plaincopyprint?

  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.  * int main( int argc, PCHAR argv[] ) 
  11.  * 功能   應用程式主函式,根據輸入的驅動器 
  12.  *      根路徑引數判斷是否為光碟機,是否放 
  13.  *      入光碟。 
  14.  * 引數   驅動器根路徑,比如“D:/”。 
  15.  **************************************/  
  16. int main( int argc, PCHAR argv[] )  
  17. {  
  18.     //儲存檔案系統類別名   
  19.     CHAR szFileSystemNameBuffer[BUFSIZE];  
  20.     DWORD dwLastError;  
  21.     DWORD dwFileSystemFlags;  
  22.     //判斷是否輸入執行時引數   
  23.     if( argc != 2 )   
  24.     {  
  25.         printf("請輸入驅動器的根路徑,比如: /"D:///"/n");   
  26.         return( -1 );  
  27.     }  
  28.     //判斷輸入的驅動器是否為CD/DVD ROM   
  29.     if(GetDriveType(argv[1])!=DRIVE_CDROM)  
  30.     {  
  31.         printf("驅動器 %s 不是 CD/DVD ROM。/n",argv[1]);  
  32.         return( -1 );  
  33.     }  
  34.     //獲取卷資訊   
  35.     if (!GetVolumeInformation(  
  36.         argv[1], NULL, 0,  
  37.         NULL,NULL,  
  38.         &dwFileSystemFlags,  
  39.         szFileSystemNameBuffer,  
  40.         BUFSIZE  
  41.         ))  
  42.     {  
  43.         dwLastError = GetLastError();  
  44.         if(dwLastError == 21)  
  45.         {  
  46.             printf("裝置未就緒,請放入光碟!/n");  
  47.             return 0;  
  48.         }  
  49.         else  
  50.         {  
  51.             printf("GetVolumeInformation 錯誤 %d/n",dwLastError);  
  52.             return 0;  
  53.         }  
  54.     }  
  55.     printf ("光碟已經放入,檔案系統類別 %s。/n",szFileSystemNameBuffer);  
  56.     return 0;  
  57. }  

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具有同樣的長度。

[cpp] view plaincopyprint?

  1. /* ************************************ 
  2.  *《精通Windows API》  
  3.  * 示例程式碼 
  4.  * diskspace.c 
  5.  * 4.2.4    獲取磁碟空間資訊 
  6.  **************************************/  
  7. /* 標頭檔案 */  
  • #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文件學習它們的使用方法。

[cpp] view plaincopyprint?

  1. /* ************************************ 
  2. *《精通Windows API》  
  3. * 示例程式碼 
  4. * wr.c 
  5. * 4.3.2 建立、開啟、讀寫檔案,獲取檔案大小 
  6. **************************************/  
  7. /* 標頭檔案 */  
  • #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的功能是一致的,都是獲取檔案大小,函式原型分別如下。

[cpp] view plaincopyprint?

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

 4.3.3 建立目錄

程式設計實現建立目錄是非常簡單的,只要使用API函式CreateDirectory即可。 1. 關鍵API (1) Createdirectory 函式原型如下: ◇引數 lpPathName:輸入引數,所要建立的目錄名或路徑。 lpSecurityAttributes:輸入引數,設定為NULL。 ◇返回值 返回BOOL值,表示是否成功。 ◇使用說明 如果程式返回失敗,可以使用GetLastError函式獲取錯誤資訊。可能的值包括ERROR ALREADY EXISTS(資料夾已經存在)和ERROR PATH NOT FOUND(路徑不存在)。

[cpp] view plaincopyprint?

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

 4.3.4 獲取程式所在的目錄、程式模組路徑,獲取和設定當前目錄

Windows系統提供一組API實現對程式執行時相關目錄的獲取和設定。使用者可以使用 GetCurrentDirectory和SetCurrentDirectory獲取程式的當前目錄,獲取模組的路徑使用 GetModuleFileName,如果以NULL引數呼叫GetModuleFileName,將會返回當前模組的路徑。如果在程式主模組(exe)中獲取當前模組路徑,便可以從當前模組的路徑中提取出程式執行時所在的路徑。 1.關鍵API (1)GetCurrentDirectory。 獲取程序的當前目錄,函式原型如下:

 (2)SetCurrentDirectory。 設定程序的當前目錄,函式原型如下:

(3)GetModuleFileName。 獲取模組檔名,當第一個引數為NULL時獲取當前模組路徑,函式原型如下:

[cpp] view plaincopyprint?

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

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結構用於表示找到的檔案,結構中包括檔案、目錄的名字,建立、最後訪問和最後寫入時間,檔案大小、檔案屬性等。

[cpp] view plaincopyprint?

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

 4.3.6 遞迴遍歷目錄樹

在例項4-10的基礎上稍加改造,進行迴圈遞迴呼叫,採用樹形結構深度遍歷的方法。可以遍歷指定目錄中的所有檔案、包括子目錄中的檔案。程式碼實現如例項4-11所示。

[cpp] 

相關推薦

精通Windows API-函式介面程式設計例項》——4檔案系統

第4章檔案系統 4.2 磁碟和驅動器管理 檔案系統的基本概念: 包括磁碟分割槽,卷,目錄,檔案物件,檔案控制代碼,檔案對映 1.磁碟分割槽: 物理磁碟,邏輯磁碟 2.卷: 也稱邏輯驅動器,是NTFS,FAT32等檔案系統組織結構的最高層. 卷是

精通Windows.API-函式介面程式設計例項》範文慶.掃描版.pdf

書籍簡介: 《精通Windows API:函式、介面、程式設計例項》共18章,分為3個部分,第1部分(第1章-第3章)介紹Windows程式設計基礎;第2部分(第4章-第17章)按照程式設計的各個方面進行劃分,包括檔案系統、記憶體管理、程序與執行緒、使用者介面、Shell程式開發、Wind

寒江獨釣-Windows核心安全程式設計筆記-4程式碼

#ifndef __CTRL2CAP_H__ #define __CTRL2CAP_H__ #pragma once typedef struct _C2P_DEV_EXT { // 結構的大小 ULONG NodeSize; // 過濾裝置物件 PDEVICE_OBJ

《TCP/IP網路程式設計4 筆記&程式碼&註釋

TCP TCP Transmission Control Protocol 傳輸控制協議,意為對資料傳輸過程的控制。 TCP/IP 協議棧 TCP/IP 協議棧分四層: 應用層 TCP層/UDP層 IP層 鏈路層 根據2.的TCP套接字還是UDP套接字

《集體智慧程式設計4 搜尋與排名 個人筆記

第4章 搜尋與排名 1、基於內容的排名 單詞頻度:位於查詢條件中的單詞在文件中出現的次數能有助於我們判斷文件的相關程度。 文件位置:文件的主題有可能會出現在靠近文件的開始處。搜尋引擎可以對待查單詞在文件中出現越早的情況給予越高的評價。 單詞距離:如果查

【作業系統】檔案系統介面

檔案系統由兩個不同部分組成: 一組檔案:檔案用於儲存相關資料 目錄結構:目錄用於組織系統內檔案並提供檔案相關資訊 10.1檔案概念 檔案是記錄在外存上的相關資訊的具有名稱的集合。 從使用者角度而言,檔案是邏輯外存的最小分配單元,即除非資料在

《Python核心程式設計9 檔案和輸入輸出 練習

9–1. 檔案過濾. 顯示一個檔案的所有行, 忽略以井號( # )開頭的行. 這個字元被用做Python , Perl, Tcl, 等大多指令碼檔案的註釋符號.附加題: 處理不是第一個字元開頭的註釋. try: f = open('test.txt') f

API介面協議API端點

1.API定義: 1)API 是用於構建應用程式軟體的一組子程式定義,協議和工具。一套明確定義的各種軟體元件之間的通訊方法,實現和其他軟體快速互動。 2)API 應用範圍很廣:從作業系統中簡單的 fork() 到我們接觸的百度地圖API,和風天氣API等 1.A

go語言函式傳遞問題(map切片介面chan)

一句話總結:map、切片、介面、函式型別、chan都是引用型別,作為函式引數傳遞不會複製一個副本。 package main import (     "fmt" ) func change(a int) {     a = 10 } func changeMap(m ma

kotlin基礎筆記之類介面函式和基本語法

純粹是個人學習總結,如有不對的地方請吐槽。 kotlin包概念 其實kotlin類和包沒有直接的聯絡,包名可以和檔案存放的路徑不一致。 比如檔案的存放地址是:com.xxx.yyy,包名可以是 package com.yyy.xxx Imports關鍵字 在java中是用於匯入的 在ko

java介面介面抽象類的區別

1、定義           Java介面是一系列方法的宣告,是一些方法特徵的集合,一個介面只有方法的特徵沒有方法的實現,因此這些方法可以在不同的地方被不同的類實現,而這些實現可以具有不同的行為(功能)。 2、Java介面與介面區別

全沾工程師----如何一個人寫完webAndroidiOS介面CMS

前言 看了文章標題,你也許嚇一跳,心想一個人有那麼牛逼嘛。就當筆者浮誇吧,不想爭辯了。這是一個神奇的時代,我這一代IT人有太多的工具。雖然我懶(其實程式設計師都懶),但是,我選擇的技術和工具仍然具有相當大的自定義空間。 這不是一篇啥好文章,但是,這篇文章可以給那些有需求全沾

TypeScript學習筆記二 -- 類介面模組

類 class Person { name; eat() { console.log('im eating'); } } var p1 = new Person(); // 類的例項化 p1.name = 'batman'; p1.eat(

用Visual C#呼叫Windows API函式

用Visual C#呼叫Windows API函式         Api函式是構築Windws應用程式的基石,每一種Windows應用程式開發工具,它提供的底層函式都間接或直接地呼叫了Windows API函式,同時為了實現功能擴充套

抽象類介面委託

抽象類:提供了部分功能的實現,不能被例項化的類,               除了不能被例項化和含有抽象方法,其餘使用和正常類使用一樣。 特點:不能被例項化      

MFC操作串列埠,詳細 複製程式碼(ActiveX控制元件和Windows API函式

/******************************************************************* *******函式功能:開啟串列埠裝置連結 *******函式名稱:OpenComm *******輸入引數:無 *******輸出引數:無 ***

python 抽象類抽象方法介面依賴注入SOLIP

python 抽象類、抽象方法、介面、依賴注入、SOLIP    1、程式設計原則:SOLIP SOLIP設計原則   1、單一責任原則(SRP)     一個物件對只應該為一個元素負責   2、開放封閉原則(OCP)     對擴充套件開放,修改封閉   3、里

抽象類介面內部類

抽象類 抽象方法和抽象類 抽象方法和抽象類必須使用abstract修飾符來定義,有抽象方法的類只能被定義為抽象類,抽象類裡可以沒有抽象方法; 規則如下: 抽象類與抽象方法必須使用abstract修飾符來修飾,抽象方法不能有方法體; 抽象類不能被例項化。即使抽象類

201711671129《Java程式設計45周學習總結

教材學習內容總結  第4章  類與物件 4.1程式語言的發展階段 面向機器—>面向過程—>面向物件(封裝性、繼承、多型) 4.2類 類的定義包含兩個部分:類宣告 和 類體 4.2.1類的宣告 類的名字要符合識別符號規定 類命名遵守

201711671106《Java程式設計學習總結

教材學習內容總結 第七週學習了第六章的介面和第七章的內部類與異常類 一、介面的定義 用關鍵字interface 定義,分為介面宣告與介面體。 例如: intercace Printable{      final int MAX=100; &nb