《精通Windows API-函数、接口、编程实例》——第4章文件系统
第4章文件系統(tǒng)
?
?
4.2 磁盤和驅(qū)動(dòng)器管理
?
?
?
?
文件系統(tǒng)的基本概念:
包括磁盤分區(qū),卷,目錄,文件對(duì)象,文件句柄,文件映射
1.磁盤分區(qū):
物理磁盤,邏輯磁盤
2.卷:
也稱邏輯驅(qū)動(dòng)器,是NTFS,FAT32等文件系統(tǒng)組織結(jié)構(gòu)的最高層.
卷是存儲(chǔ)設(shè)備(硬盤)上由文件系統(tǒng)管理的一塊區(qū)域,在邏輯上相互隔離的存儲(chǔ)單元.
windows命名規(guī)則:
主文件名+擴(kuò)展名
windows中文件系統(tǒng)的長(zhǎng)度被限制為260個(gè)字符.
這260個(gè)字符包括卷標(biāo),路徑,主文件名和擴(kuò)展名,分隔符
在DOS下的保留設(shè)備名不能做文件名或主文件名.如CON,PRN,AUX,NUL,COM1.....
=================================================================
磁盤和驅(qū)動(dòng)器管理API
GetLogicalDrivers??? ?? 獲取主機(jī)中所有的邏輯驅(qū)動(dòng)器,以Bit Map的形式返回.
GetLogicalDriverString ?? 獲取主機(jī)中所有的邏輯驅(qū)動(dòng)器,以驅(qū)動(dòng)器根路徑字符串返回.
FindFirstVolume ??? 查找主機(jī)中的第一個(gè)驅(qū)動(dòng)器,返回查找句柄.
FindNextVolume ???? 根據(jù)FindFirstVolume返回句柄,查找主機(jī)中后繼的邏輯驅(qū)動(dòng)器
FindVolumeClose ??? 關(guān)閉驅(qū)動(dòng)器查找句柄
GetDriveType ???? 獲取驅(qū)動(dòng)器類型
GetVolumeInformation ?? 獲取邏輯驅(qū)動(dòng)器信息
FindFirstVolumeMountPoint 查找指定卷的第一個(gè)掛載點(diǎn),返回查找句柄
FindNextVolumeMountPoint 根據(jù)FindFirstVolumeMountPoint返回的句柄,查找卷的后繼掛載點(diǎn).
FindVolumeMountPointClose 關(guān)閉掛載點(diǎn)查找句柄
GetVolumeNameForVolumeMountPoint 根據(jù)指定掛載點(diǎn)獲取相應(yīng)的卷設(shè)備名
SetVolumeMountPoint???????? 將指定卷掛載到指定掛載點(diǎn)處
GetDiskFreeSpace??????????? 獲取磁盤空間信息,包括每簇的扇區(qū)數(shù),每扇區(qū)的字節(jié)數(shù),簇?cái)?shù)量,空閑的簇?cái)?shù)量
GetDiskFreeSpaceEx????????? 獲取用戶可用的空閑空間的字節(jié)數(shù),磁盤總?cè)萘康淖止?jié)數(shù)
文件和目錄管理API
DeleteFile????????????????? 刪除參數(shù)所指定文件
CopyFile??????????????????? 復(fù)制指定文件為一個(gè)新文件
MoveFile??????????????????? 將指定文件或目錄移動(dòng)到指定位置
CreateFile????????????????? 新建或打開一個(gè)文件,獲取文件句柄
ReadFile??????????????????? 讀取由文件句柄指定文件的內(nèi)容
WriteFile?????????????????? 向由文件句柄指定的文件中寫入內(nèi)容
GetFileSize???????????????? 獲取文件大小,返回DWORD中;大小超出DWORD最大值時(shí)可指定高32位的DWORD聯(lián)合存儲(chǔ)
GetFileSizeEx?????????????? 獲取文件大小,存儲(chǔ)到一個(gè)64位的大整數(shù)聯(lián)合體中.
CreateDirectory???????????? 創(chuàng)建一個(gè)目錄
GetCurrentDirectory???????? 獲取當(dāng)前程序所在目錄
SetCurrentDirectory???????? 設(shè)置當(dāng)前程序所在目錄
GetModuleFileName?????????? 獲取當(dāng)前模塊全路徑
FindFirstFile?????????????? 查找指定目錄下第一個(gè)文件句柄或目錄,獲得查找句柄
FindNextFile??????????????? 根據(jù)FindFirstFile獲得的句柄,循環(huán)查找文件或目錄
GetFileAttributes?????????? 獲取指定文件目錄屬性,返回一個(gè)DWORD值
GetFileAttributesEx???????? 獲取文件或目錄屬性,存儲(chǔ)在WIN32_FILE_ATTRIBUTE_DATA結(jié)構(gòu)體中
SetFileAttributes?????????? 將文件屬性設(shè)定為指定值
FileTimeToLocalFileTime???? 將文件時(shí)間轉(zhuǎn)換為本地時(shí)間
FileTimeToSystemTime??????? 將文件轉(zhuǎn)換為系統(tǒng)時(shí)間,SYSTEMTIME格式便于顯示
高級(jí)文件操作
CreateFileMapping?????????? 創(chuàng)建文件的映射對(duì)象
MapViewOfFile?????????????? 創(chuàng)建視圖,將創(chuàng)建的文件映射對(duì)象映射到當(dāng)前進(jìn)程的地址空間中
FlushViewOfFile???????????? 將視圖中的數(shù)據(jù)都寫入磁盤,對(duì)視圖的操作都會(huì)反映到磁盤上的文件中
OpenFileMapping???????????? 打開已經(jīng)存在的命名的文件映射對(duì)象
UnmapViewOfFile???????????? 取消文件映射
GetMappedFileName?????????? 從映射對(duì)象獲取被映射文件的文件設(shè)備名
QueryDosDevice????????????? 獲取MS-DOS設(shè)備名
=================================================================
2 磁盤和驅(qū)動(dòng)器管理
◇使用兩種方法來遍歷驅(qū)動(dòng)器并獲取驅(qū)動(dòng)器屬性。
◇使用API操作驅(qū)動(dòng)器掛載點(diǎn)。
◇判斷光驅(qū)中是否有光盤。
◇獲取磁盤剩余空間、扇區(qū)信息等。
?
?
4.2.1 遍歷卷并獲取屬性
用到的API函數(shù):
?
(1) GetLogicalDrives。
獲取主機(jī)中所有的邏輯驅(qū)動(dòng)器,以BitMap的形式返回,其函數(shù)原型如下:
(2) GetLogicalDriverStrings。
獲取主機(jī)中所有驅(qū)動(dòng)器,以驅(qū)動(dòng)器根路徑字符串返回,其函數(shù)原型如下:
(3)FindFirstVolume。
查找主機(jī)中的第一個(gè)驅(qū)動(dòng)器,返回驅(qū)動(dòng)器設(shè)備名,其函數(shù)原型如下:
(4)FindNextVolume
查找主機(jī)中后繼的邏輯驅(qū)動(dòng)器,其函數(shù)原型如下:
(5)FindVo1umeClose。
\關(guān)閉FindFirstVolume打開的卷遍歷句柄,其函數(shù)原型如下:
(6) GetDriveType。
獲取驅(qū)動(dòng)器類型,其函數(shù)原型如下:
(7) GetVolumeInformation。
獲取邏輯驅(qū)動(dòng)器信息,其函數(shù)原型如下:
???
?
[cpp] view plaincopyprint?/* ************************************ *《精通Windows API》 * 示例代碼 * GetVolumeInfo.c * 4.2.1 遍歷驅(qū)動(dòng)器并獲取驅(qū)動(dòng)器屬性 **************************************/ /* 頭文件 */ #include <windows.h> #include <stdlib.h> #include <stdio.h> #include <string.h> /* 預(yù)定義 */ #define BUFSIZE 1024 /* 函數(shù)申明 */ BOOL GetDirverInfo(LPSTR szDrive); /* ************************************ * 功能 應(yīng)用程序主函數(shù),遍歷驅(qū)動(dòng)器并調(diào)用 * GetDirverInfo 獲取驅(qū)動(dòng)器屬性 **************************************/ void main(void) { CHAR szLogicalDriveStrings[BUFSIZE]; PCHAR szDrive; ZeroMemory(szLogicalDriveStrings,BUFSIZE); // 獲取邏輯驅(qū)動(dòng)器卷標(biāo)名 GetLogicalDriveStrings(BUFSIZE - 1,szLogicalDriveStrings); szDrive = (PCHAR)szLogicalDriveStrings; // 循環(huán)處理每個(gè)卷 do { if(!GetDirverInfo(szDrive)) { printf("/nGet Volume Information Error: %d", GetLastError()); } szDrive += (lstrlen(szDrive)+1); } while(*szDrive!='/x00'); } /* ************************************ * BOOL GetDirverInfo(LPSTR szDrive) * 功能 獲取驅(qū)動(dòng)器的屬性 * 參數(shù) LPSTR szDrive * 指明要獲取屬性的驅(qū)動(dòng)器的根路徑 如 C:/ * 返回值 BOOL 是否成功 **************************************/ BOOL GetDirverInfo(LPSTR szDrive) { UINT uDriveType; DWORD dwVolumeSerialNumber; DWORD dwMaximumComponentLength; DWORD dwFileSystemFlags; TCHAR szFileSystemNameBuffer[BUFSIZE]; printf("/n%s/n",szDrive); uDriveType = GetDriveType(szDrive); // 判斷類型 switch(uDriveType) { case DRIVE_UNKNOWN: printf("The drive type cannot be determined. 未知的磁盤類型 "); break; case DRIVE_NO_ROOT_DIR: printf("The root path is invalid, for example, no volume is mounted at the path. 說明lpRootPathName是無效的 "); break; case DRIVE_REMOVABLE: printf("The drive is a type that has removable media, for example, a floppy drive or removable hard disk. 可移動(dòng)磁盤 "); break; case DRIVE_FIXED: printf("The drive is a type that cannot be removed, for example, a fixed hard drive. 固定磁盤 "); break; case DRIVE_REMOTE: printf("The drive is a remote (network) drive. 網(wǎng)絡(luò)磁盤 "); break; case DRIVE_CDROM: printf("The drive is a CD-ROM drive. 光驅(qū) "); break; case DRIVE_RAMDISK: printf("The drive is a RAM disk. "); break; default: break; } if (!GetVolumeInformation( szDrive, NULL, 0, &dwVolumeSerialNumber, &dwMaximumComponentLength, &dwFileSystemFlags, szFileSystemNameBuffer, BUFSIZE )) { return FALSE; } printf ("/nVolume Serial Number is 存儲(chǔ)驅(qū)動(dòng)器序列號(hào)%u",dwVolumeSerialNumber); printf ("/nMaximum Component Length is 文件系統(tǒng)所支持的文件組成部分的最大值%u",dwMaximumComponentLength); printf ("/nSystem Type is文件系統(tǒng)類 %s/n",szFileSystemNameBuffer); if(dwFileSystemFlags & FILE_SUPPORTS_REPARSE_POINTS) { printf ("The file system does not support volume mount points./n"); } if(dwFileSystemFlags & FILE_VOLUME_QUOTAS) { printf ("The file system supports disk quotas./n"); } if(dwFileSystemFlags & FILE_CASE_SENSITIVE_SEARCH) { printf ("The file system supports case-sensitive file names./n"); } //you can use these value to get more informaion // //FILE_CASE_PRESERVED_NAMES //FILE_CASE_SENSITIVE_SEARCH //FILE_FILE_COMPRESSION //FILE_NAMED_STREAMS //FILE_PERSISTENT_ACLS //FILE_READ_ONLY_VOLUME //FILE_SUPPORTS_ENCRYPTION //FILE_SUPPORTS_OBJECT_IDS //FILE_SUPPORTS_REPARSE_POINTS //FILE_SUPPORTS_SPARSE_FILES //FILE_UNICODE_ON_DISK //FILE_VOLUME_IS_COMPRESSED //FILE_VOLUME_QUOTAS printf(".../n"); return TRUE; }??
?
?
?
?4.2.2 操作驅(qū)動(dòng)器掛載點(diǎn)
一般可以用FindFirstVolumeMountPoint系列的API來找到一個(gè)卷的所有掛載點(diǎn);用
GetVolumeNameForVolumeMountPoint來獲取指定掛載點(diǎn)所指向的卷名,卷名形式為"//?/Volume{GUID}/”;用SetVolumeMountPoint來設(shè)置新的掛載點(diǎn)。
通過系統(tǒng)的磁盤管理功能可以設(shè)置卷的掛載點(diǎn),如圖4-2所示。
◇“我的電腦”圖標(biāo)右鍵菜單中選擇“管理”。
◇彈出“計(jì)算機(jī)管理”窗口,選擇“磁盤管理”。
◇選中需要掛載的卷,在右鍵菜單中選擇“更改驅(qū)動(dòng) 器名和路徑”。
◇在彈出的對(duì)話框中單擊“添加”按鈕,選擇“裝入 以下空白NTFS文件夾”。
◇選擇需要將卷掛載入的文件夾(空白),單擊“確定”按鈕。
◇卷就被裝入文件夾中,之后就可以和訪問文件夾一個(gè)訪問這個(gè)卷了,如圖4-3和4-4
?
(1)FindFirstVolumeMountPoint.
獲取指定卷的第一個(gè)掛載點(diǎn),函數(shù)原型如下:
以用GetLastError()函數(shù)獲取更詳細(xì)的錯(cuò)誤信息。
(2) FindNextVolumeMountPoint
查找指定卷的后繼掛載點(diǎn),函數(shù)原型如下:
(3)FindVolumeMountPointClose.
關(guān)閉FindVolumeMountPointClose打開的卷句柄,其函數(shù)原型如下:
◇參數(shù)
hFindVolumeMountPoint:要關(guān)閉的掛載點(diǎn)查找句柄。
◇返回值
(4)GetVolumeNameForVolumeMountPoint。
根據(jù)指定的掛載點(diǎn)獲取相應(yīng)的卷設(shè)備名,函數(shù)原型如下:
(5)SetVolumeMountPc
將指定卷掛載到指定掛載點(diǎn)處,函數(shù)原型如下:
/* ************************************ *《Windows應(yīng)用程序開發(fā)》 * 示例代碼 * mount.c * 4.2.2 卷掛載點(diǎn)操作 **************************************/ /* 預(yù)編譯聲明 */ #define _WIN32_WINNT 0x0501 #include <windows.h> #include <stdio.h> #include <tchar.h> #define BUFSIZE MAX_PATH #define FILESYSNAMEBUFSIZE MAX_PATH /* ************************************ * ProcessVolumeMountPoint * 功能 列舉掛載點(diǎn) **************************************/ BOOL ProcessVolumeMountPoint (HANDLE hPt, TCHAR *PtBuf, DWORD dwPtBufSize, TCHAR *Buf) { BOOL bFlag; // 結(jié)果 TCHAR Path[BUFSIZE]; // 全路徑 TCHAR Target[BUFSIZE]; // 掛載點(diǎn)設(shè)備 printf ("/tVolume mount point found is /"%s/"/n", PtBuf); lstrcpy (Path, Buf); lstrcat (Path, PtBuf); bFlag = GetVolumeNameForVolumeMountPoint( Path, Target, BUFSIZE ); if (!bFlag) printf ("/tAttempt to get volume name for %s failed./n", Path); else printf ("/tTarget of the volume mount point is %s./n", Target); bFlag = FindNextVolumeMountPoint( hPt, PtBuf, dwPtBufSize ); return (bFlag); } /* ************************************ * ProcessVolume * 功能 判斷卷類型,列舉掛載點(diǎn) **************************************/ BOOL ProcessVolume (HANDLE hVol, TCHAR *Buf, DWORD iBufSize) { BOOL bFlag; // 返回標(biāo)志 HANDLE hPt; // 卷句柄 TCHAR PtBuf[BUFSIZE]; // 掛載點(diǎn)路徑 DWORD dwSysFlags; // 文件系統(tǒng)標(biāo)記 TCHAR FileSysNameBuf[FILESYSNAMEBUFSIZE]; printf ("Volume found is /"%s/"./n", Buf); // 是否NTFS GetVolumeInformation( Buf, NULL, 0, NULL, NULL, &dwSysFlags, FileSysNameBuf, FILESYSNAMEBUFSIZE); if (! (dwSysFlags & FILE_SUPPORTS_REPARSE_POINTS)) { printf ("/tThis file system does not support volume mount points./n"); } else { // 本卷中的掛載點(diǎn) hPt = FindFirstVolumeMountPoint( Buf, // 卷的跟跟蹤 PtBuf, // 掛載點(diǎn)路徑 BUFSIZE ); if (hPt == INVALID_HANDLE_VALUE) { printf ("/tNo volume mount points found!/n"); } else { // 處理掛載點(diǎn) bFlag = ProcessVolumeMountPoint (hPt, PtBuf, BUFSIZE, Buf); // 循環(huán) while (bFlag) bFlag = ProcessVolumeMountPoint (hPt, PtBuf, BUFSIZE, Buf); // 結(jié)束 FindVolumeMountPointClose(hPt); } } // 下一個(gè) bFlag = FindNextVolume( hVol, Buf, iBufSize); return (bFlag); } /* ************************************ * int GetMountPoint(void) * 功能 獲取掛載點(diǎn) **************************************/ int GetMountPoint(void) { TCHAR buf[BUFSIZE]; // 卷標(biāo)識(shí)符 HANDLE hVol; // 卷句柄 BOOL bFlag; // 結(jié)果標(biāo)志 printf("Volume mount points info of this computer:/n/n"); // 打開卷 hVol = FindFirstVolume (buf, BUFSIZE ); if (hVol == INVALID_HANDLE_VALUE) { printf ("No volumes found!/n"); return (-1); } bFlag = ProcessVolume (hVol, buf, BUFSIZE); while (bFlag) { bFlag = ProcessVolume (hVol, buf, BUFSIZE); } bFlag = FindVolumeClose( hVol ); return (bFlag); } /* ************************************ * void Usage (PCHAR argv) * 功能 使用方法 **************************************/ void Usage (PCHAR argv) { printf( "/n/n/t%s, mount a volume at a mount point./n", argv ); printf( "/tFor example, /"mount D://mnt//drives// E:///"/n" ); } /* ************************************ * main * 功能 入口函數(shù) **************************************/ int main( int argc, PCHAR argv[] ) { BOOL bFlag; CHAR Buf[BUFSIZE]; if( argc != 3 ) { GetMountPoint(); Usage( argv[0] ); return( -1 ); } bFlag = GetVolumeNameForVolumeMountPoint( argv[2], // 輸入掛載點(diǎn)或目錄 Buf, // 輸出卷名 BUFSIZE ); if (bFlag != TRUE) { printf( "Retrieving volume name for %s failed./n", argv[2] ); return (-2); } printf( "Volume name of %s is %s/n", argv[2], Buf ); bFlag = SetVolumeMountPoint( argv[1], // 掛載點(diǎn) Buf // 需要掛載的卷 ); if (!bFlag) { printf ("Attempt to mount %s at %s failed. error code is/n", argv[2], argv[1], GetLastError()); } return (bFlag); }
?
?
4.2.3 判斷光驅(qū)中是否有光盤
判斷光驅(qū)中是否有光盤,仍然可以使用在4.2.1小節(jié)介紹的GetDriveType和GetVolumeInformation函數(shù)實(shí)現(xiàn)。首先使用驅(qū)動(dòng)器根路徑作為GetDriveType和參數(shù),如果返回值是DRIVE_CDROM,則說明此驅(qū)動(dòng)器為光驅(qū)。然后使用GetVolumeInformation獲取信息,如果成功,則說明存光盤已經(jīng)放入。調(diào)用完成后GetVolumeInformation函數(shù)的第7個(gè)參數(shù)LPTSTR lpFileSystemNameBuffer存儲(chǔ)的是文件系統(tǒng)的類別字符串,光盤一般是CDFS。如果調(diào)用GetVolumeInformation時(shí)返回FALSE,并且GetLastError返回21,則說明驅(qū)動(dòng)器中未放入光盤。 1.關(guān)鍵API(1)GetDiskType與GetVolumeInformation。
這兩個(gè)API已經(jīng)在4.2.1小節(jié)介紹過,這里不再贅述。
(2)GetLastError。
獲取在執(zhí)行中本線程最近的一次錯(cuò)誤。本函數(shù)是很多系統(tǒng)API返回執(zhí)行錯(cuò)誤原因的方法。可能使用SetLastError函數(shù)設(shè)置本線程的Last-Error值。GetLastError函數(shù)原型如下: [cpp] view plaincopyprint?
4.2.4 獲取磁盤分區(qū)的總?cè)萘俊⒖臻e容量、簇、扇區(qū)信息
獲取磁盤分區(qū)的總?cè)萘亢涂臻e空間的容量可以使用GetDiskFreeSpace函數(shù)或GetDiskFree SpaceEx函數(shù)。GetDiskFreeSpace使用DWORD類型作為輸出參數(shù),由于DWOR長(zhǎng)度為32位,最大只能表示4GB,而一般的磁盤分區(qū)大小都大于4GB,所以,GetDiskFreeSpace并不直接返回磁盤的總?cè)萘亢涂臻e空間的容量,而是使用總簇?cái)?shù)、空閑的簇?cái)?shù)、每簇的扇區(qū)數(shù)、每扇區(qū)的字節(jié)數(shù)來表示。用戶在編程時(shí),可以使用它們的乘積來獲得最終結(jié)果。而GetDiskFreeSpaceEx使用ULARGE_INTEGER (DWORD64)類型的數(shù)據(jù)來存儲(chǔ)磁盤空間總空間和剩余空間,所以可以直接獲得結(jié)果。DWORD64可以表示約16777216TB的數(shù)據(jù)量(DWORD64最大可表示2Byte,lTB=2Byte,
(2)GetDiskFreeSpacEX。
獲取驅(qū)動(dòng)器根路徑作為輸入,獲取用戶可用的空閑空間的字節(jié)數(shù)、空閑空間的字節(jié)數(shù)、磁盤總?cè)萘康淖止?jié)數(shù),其函數(shù)原型如下:
2.關(guān)鍵數(shù)據(jù)結(jié)構(gòu)
GetDiskFreeSpaceEx函數(shù)使用到了數(shù)據(jù)結(jié)構(gòu)ULARGE_INTEGER,數(shù)據(jù)類型PULARGE
INTEGER是指向它的指針。ULARGE__ INTEGER的定義如下,此數(shù)據(jù)結(jié)構(gòu)使用兩個(gè)DWORD來表
示64位數(shù)據(jù)。低位存儲(chǔ)于前,高位存儲(chǔ)于后,與DWORD64的存儲(chǔ)形式是一致的,所以可以直接強(qiáng)制類型轉(zhuǎn)換為DOWRD64類型。也可以直接使用QuadPart成員,QuadPart成員是ULONGLONG形數(shù)據(jù)結(jié)構(gòu),在一般32位主機(jī)上,與DWORD64具有同樣的長(zhǎng)度。
- #include?<windows.h> ??
- #include?<stdio.h> ??
- ??
- /*?************************************?
- ?*?BOOL?GetDiskSpaceInfo(LPCSTR?pszDrive?
- ?*?功能???根據(jù)輸入的驅(qū)動(dòng)器,獲取磁盤總?cè)萘?/span>?
- ?*??????????空閑空間、簇?cái)?shù)量等磁盤信息?
- ?*?參數(shù)???驅(qū)動(dòng)器根路徑,比如“D:/”。?
- ?**************************************/??
- BOOL?GetDiskSpaceInfo(LPCSTR?pszDrive)??
- {??
- ????DWORD64?qwFreeBytesToCaller,?qwTotalBytes,?qwFreeBytes;??
- ????DWORD?dwSectPerClust,?dwBytesPerSect,?dwFreeClusters,??dwTotalClusters;??
- ????BOOL?bResult;??
- ??????
- ????//使用GetDiskFreeSpaceEx獲取磁盤信息并打印結(jié)果 ??
- ????bResult?=?GetDiskFreeSpaceEx?(pszDrive,??
- ????????(PULARGE_INTEGER)&qwFreeBytesToCaller,??
- ????????(PULARGE_INTEGER)&qwTotalBytes,??
- ????????(PULARGE_INTEGER)&qwFreeBytes);??
- ??
- ????if(bResult)???
- ????{??
- ????????printf("使用GetDiskFreeSpaceEx獲取磁盤空間信息/n");??
- ????????printf("可獲得的空閑空間(字節(jié)):?/t%I64d/n",?qwFreeBytesToCaller);??
- ????????printf("空閑空間(字節(jié)):?/t/t%I64d/n",?qwFreeBytes);??
- ????????printf("磁盤總?cè)萘?#xff08;字節(jié)):?/t/t%I64d/n",?qwTotalBytes);??
- ????}??
- ??
- ????//使用GetDiskFreeSpace獲取磁盤信息并打印結(jié)果 ??
- ????bResult?=?GetDiskFreeSpace?(pszDrive,???
- ????????&dwSectPerClust,???
- ????????&dwBytesPerSect,??
- ????????&dwFreeClusters,???
- ????????&dwTotalClusters);??
- ??
- ????if(bResult)???
- ????{??
- ????????printf("/n使用GetDiskFreeSpace獲取磁盤空間信息/n");??
- ????????printf("空閑的簇?cái)?shù)量?:?/t/t/t%d/n",dwFreeClusters);??
- ????????printf("總簇?cái)?shù)量?:?/t/t/t%d/n",dwTotalClusters);??
- ????????printf("每簇的扇區(qū)數(shù)量?:?/t/t%d/n",dwSectPerClust);??
- ????????printf("每扇區(qū)的容量(字節(jié)):?/t/t%d/n",dwBytesPerSect);??
- ????????printf("空閑空間(字節(jié)):?/t/t%I64d/n",???
- ????????????(DWORD64)dwFreeClusters*??
- ????????????(DWORD64)dwSectPerClust*(DWORD64)dwBytesPerSect);??
- ????????printf("磁盤總?cè)萘?#xff08;字節(jié)):?/t/t%I64d",??
- ????????????(DWORD64)dwTotalClusters*??
- ????????????(DWORD64)dwSectPerClust*(DWORD64)dwBytesPerSect);??
- ????}??
- ????return?bResult;??
- }??
- ??
- /*?************************************?
- ?*?int?main(?int?argc,?PCHAR?argv[]?)?
- ?*?功能???應(yīng)用程序主函數(shù),根據(jù)輸入?yún)?shù)?
- ?*??????????調(diào)用GetDiskSpaceInfo函數(shù)獲取?
- ?*??????????磁盤空間信息?
- ?*?參數(shù)???驅(qū)動(dòng)器根路徑,比如“D:/”。?
- ?**************************************/??
- int?main(int?argc,?PCHAR?argv[])??
- {??
- ????GetDiskSpaceInfo?(argv[1]);??
- }??
/* ************************************ *《精通Windows API》 * 示例代碼 * diskspace.c * 4.2.4 獲取磁盤空間信息 **************************************/ /* 頭文件 */ #include <windows.h> #include <stdio.h> /* ************************************ * BOOL GetDiskSpaceInfo(LPCSTR pszDrive * 功能 根據(jù)輸入的驅(qū)動(dòng)器,獲取磁盤總?cè)萘?* 空閑空間、簇?cái)?shù)量等磁盤信息 * 參數(shù) 驅(qū)動(dòng)器根路徑,比如“D:/”。 **************************************/ BOOL GetDiskSpaceInfo(LPCSTR pszDrive) { DWORD64 qwFreeBytesToCaller, qwTotalBytes, qwFreeBytes; DWORD dwSectPerClust, dwBytesPerSect, dwFreeClusters, dwTotalClusters; BOOL bResult; //使用GetDiskFreeSpaceEx獲取磁盤信息并打印結(jié)果 bResult = GetDiskFreeSpaceEx (pszDrive, (PULARGE_INTEGER)&qwFreeBytesToCaller, (PULARGE_INTEGER)&qwTotalBytes, (PULARGE_INTEGER)&qwFreeBytes); if(bResult) { printf("使用GetDiskFreeSpaceEx獲取磁盤空間信息/n"); printf("可獲得的空閑空間(字節(jié)): /t%I64d/n", qwFreeBytesToCaller); printf("空閑空間(字節(jié)): /t/t%I64d/n", qwFreeBytes); printf("磁盤總?cè)萘?#xff08;字節(jié)): /t/t%I64d/n", qwTotalBytes); } //使用GetDiskFreeSpace獲取磁盤信息并打印結(jié)果 bResult = GetDiskFreeSpace (pszDrive, &dwSectPerClust, &dwBytesPerSect, &dwFreeClusters, &dwTotalClusters); if(bResult) { printf("/n使用GetDiskFreeSpace獲取磁盤空間信息/n"); printf("空閑的簇?cái)?shù)量 : /t/t/t%d/n",dwFreeClusters); printf("總簇?cái)?shù)量 : /t/t/t%d/n",dwTotalClusters); printf("每簇的扇區(qū)數(shù)量 : /t/t%d/n",dwSectPerClust); printf("每扇區(qū)的容量(字節(jié)): /t/t%d/n",dwBytesPerSect); printf("空閑空間(字節(jié)): /t/t%I64d/n", (DWORD64)dwFreeClusters* (DWORD64)dwSectPerClust*(DWORD64)dwBytesPerSect); printf("磁盤總?cè)萘?#xff08;字節(jié)): /t/t%I64d", (DWORD64)dwTotalClusters* (DWORD64)dwSectPerClust*(DWORD64)dwBytesPerSect); } return bResult; } /* ************************************ * int main( int argc, PCHAR argv[] ) * 功能 應(yīng)用程序主函數(shù),根據(jù)輸入?yún)?shù) * 調(diào)用GetDiskSpaceInfo函數(shù)獲取 * 磁盤空間信息 * 參數(shù) 驅(qū)動(dòng)器根路徑,比如“D:/”。 **************************************/ int main(int argc, PCHAR argv[]) { GetDiskSpaceInfo (argv[1]); }
?
?
?
4.3 文件和目錄管理
文件和目錄管理是Windows系統(tǒng)編程最為基本的內(nèi)容,幾乎所有的應(yīng)用程序都會(huì)使用到文件和目錄的操作。本節(jié)將向讀者演示如何創(chuàng)建目錄、遍歷目錄、創(chuàng)建文件、打開文件、讀寫文件、移動(dòng)復(fù)制刪除文件等。本節(jié)通過以下多個(gè)實(shí)例來講解Windows API對(duì)文件和目錄的管理。
◇刪除、復(fù)制、重命名、移動(dòng)文件。
◇創(chuàng)建、打開、讀寫文件。
◇創(chuàng)建、打開目錄。
◇獲取當(dāng)前目錄、獲取程序所在的目錄、獲取模塊路徑。
◇查找文件、遍歷目錄下的文件和子目錄。
◇遞歸遍歷目錄樹。
◇獲取、設(shè)置文件屬性和時(shí)間。
4.3.1 刪除、復(fù)制、重命名、移動(dòng)文件
Windows系統(tǒng)為文件的刪除、復(fù)制、重命名或移動(dòng)文件提供了相應(yīng)的API函數(shù)。刪除文件使用DeleteFile函數(shù);復(fù)制文件使用CopyFile函數(shù);重命名文件和移動(dòng)文件實(shí)際是一個(gè)操作,使用MoveFile函數(shù)。這幾個(gè)函數(shù)的使用都非常簡(jiǎn)單,下面分別介紹。
1.關(guān)鍵API
(1) DeleteFile。
DeleteFile的功能是刪除文件。以文件路徑作為輸入,指向需要?jiǎng)h除的文件。文件路徑可以是類似于“c:/files/delete.txt”的絕對(duì)路徑,也可以是類似于“./delete.txt”的相對(duì)路徑,二相對(duì)于可執(zhí)行文件所在的路徑。
(2) CopyFile。
CopyFile的功能是復(fù)制文件。通過參數(shù)輸入復(fù)制文件和源路徑和目的路徑,路徑可以是絕對(duì)路徑也可以是相對(duì)路徑,還可以通過參數(shù)指明如果目的路徑已經(jīng)存在文件,是否覆蓋。可以使用CopyFileEx函數(shù)進(jìn)行更為高級(jí)的操作,比如在復(fù)制進(jìn)行過程中取消復(fù)制等。CopyFileEx可以指定
一個(gè)回調(diào)函數(shù)來處理文件復(fù)制中所可能發(fā)生的各種情況。
3) MoveFile。
MoveFile的功能是移動(dòng)、重命名文件和目錄。通過參數(shù)輸入源路徑和目的路徑,路徑可以是絕對(duì)路徑也可以是相對(duì)路徑,如果目的路徑的文件或目錄已經(jīng)存在,則返回失敗。可以使用MoveFileEx函數(shù)來指定更多的選項(xiàng),如果已經(jīng)存在是否替換等。還可以使用MoveFileWithProgress指定一個(gè)回調(diào)函數(shù)來處理文件移動(dòng)中所可能發(fā)生的各種情況。函數(shù)原型如下:
(4) CopyFileEx、MoveFileEx以及MoveFileWithProgreSS.
這3個(gè)API函數(shù)功能更豐富,但是限于篇幅這里不再做詳細(xì)介紹,讀者可以使用SDK文檔學(xué)習(xí)它們的使用方法。
?
?
[cpp] view plaincopyprint?- #include?<windows.h> ??
- #include?<stdio.h> ??
- ??
- /*?************************************?
- *?DWORD?ReadFileContent(LPSTR?szFilePath)?
- *?功能????獲取文件大小?
- *???????讀取文件內(nèi)容,并以16進(jìn)制的形式打印出來?
- *?參數(shù)????LPSTR?szFilePath?
- *???????文件路徑?
- **************************************/??
- DWORD?ReadFileContent(LPSTR?szFilePath)??
- {??
- ????//文件大小 ??
- ????HANDLE?hFileRead;??
- ????//保存文件大小 ??
- ????LARGE_INTEGER?liFileSize;??
- ????//成功讀取的文件數(shù)據(jù)大小 ??
- ????DWORD?dwReadedSize;??
- ????//累加計(jì)算已經(jīng)讀取數(shù)據(jù)的大小 ??
- ????LONGLONG?liTotalRead?=?0;??
- ????//文件數(shù)據(jù)緩存 ??
- ????BYTE?lpFileDataBuffer[32];??
- ??
- ????//打開已經(jīng)存在的文件,讀取內(nèi)容。??? ??
- ????hFileRead?=?CreateFile(szFilePath,//?要打開的文件名 ??
- ????????GENERIC_READ,??????????????//?以讀方式打開 ??
- ????????FILE_SHARE_READ,???????????//?可共享讀 ??
- ????????NULL,??????????????????????//?默認(rèn)安全設(shè)置 ??
- ????????OPEN_EXISTING,?????????????//?只打開已經(jīng)存在的文件 ??
- ????????FILE_ATTRIBUTE_NORMAL,?????//?常規(guī)文件屬性 ??
- ????????NULL);?????????????????????//?無模板 ??
- ??
- ????//打開文件是否成功。 ??
- ????if(hFileRead==INVALID_HANDLE_VALUE)??
- ????{??
- ????????printf("打開文件失敗:%d",GetLastError());??
- ????}??
- ??
- ????if(!GetFileSizeEx(hFileRead,&liFileSize))??
- ????{??
- ????????printf("獲取文件大小失敗:%d",GetLastError());??
- ????}??
- ????else??
- ????{??
- ????????printf("文件大小為:%d/n",liFileSize.QuadPart);??
- ????}??
- ??
- ????//循環(huán)讀取并打印文件內(nèi)容 ??
- ????while(TRUE)??
- ????{??
- ????????DWORD?i;??
- ??
- ????????if(!ReadFile(hFileRead,?//讀文件的句柄 ??
- ????????????lpFileDataBuffer,???//存儲(chǔ)讀取的文件內(nèi)容 ??
- ????????????32,?????????????????//讀的大小(字節(jié)) ??
- ????????????&dwReadedSize,??????//實(shí)際讀取的大小 ??
- ????????????NULL))??????????????//不使用Overlapped ??
- ????????{??
- ????????????printf("讀文件錯(cuò)誤:%d/n",GetLastError());??
- ????????????break;??
- ????????}??
- ????????printf("讀取了%d字節(jié),文件內(nèi)容是:",dwReadedSize);??
- ??????????
- ????????for(i=0;?i<dwReadedSize;?i++)??
- ????????{??
- ????????????printf("0x%x?",lpFileDataBuffer[i]);??
- ????????}??
- ????????printf("/n");??
- ????????liTotalRead?+=?dwReadedSize;??
- ????????if(liTotalRead?==?liFileSize.QuadPart)??
- ????????{??
- ????????????printf("讀文件結(jié)束/n");??
- ????????????break;??
- ????????}??
- ????}??
- ????CloseHandle(hFileRead);??
- ????return?0;??
- }??
- ??
- /*?************************************?
- *??SaveDataToFile?
- *?功能????將數(shù)據(jù)存儲(chǔ)到文件末尾?
- *?參數(shù)????LPSTR?szFilePath????文件路徑?
- *???????LPVOID?lpData???????需存儲(chǔ)的數(shù)據(jù)?
- *???????DWORD?dwDataSize????數(shù)據(jù)大小(字節(jié))?
- **************************************/??
- DWORD?SaveDataToFile(??
- ?????????????????????LPSTR?szFilePath,??
- ?????????????????????LPVOID?lpData,??
- ?????????????????????DWORD?dwDataSize)??
- {??
- ????//文件句柄 ??
- ????HANDLE?hFileWrite;??
- ????//成功寫入的數(shù)據(jù)大小 ??
- ????DWORD?dwWritedDateSize;??
- ??
- ????//打開已經(jīng)存在的文件,讀取內(nèi)容。??? ??
- ????hFileWrite?=?CreateFile(szFilePath,?//?要打開的文件名 ??
- ????????GENERIC_WRITE,??????????//?以寫方式打開 ??
- ????????0,??????????????????????//?可共享讀 ??
- ????????NULL,???????????????????//?默認(rèn)安全設(shè)置 ??
- ????????OPEN_ALWAYS,????????????//?打開已經(jīng)存在的文件,沒用則創(chuàng)建 ??
- ????????FILE_ATTRIBUTE_NORMAL,??//?常規(guī)文件屬性 ??
- ????????NULL);??????????????????//?無模板 ??
- ??????
- ????//判斷是否打開成功 ??
- ????if(hFileWrite==INVALID_HANDLE_VALUE)??
- ????{??
- ????????printf("打開文件失敗:%d/n",GetLastError());??
- ????}??
- ??
- ????//設(shè)置文件指針到文件尾 ??
- ????SetFilePointer(hFileWrite,0,0,FILE_END);??
- ??
- ????//將數(shù)據(jù)寫入文件 ??
- ????if(!WriteFile(hFileWrite,lpData,dwDataSize,&dwWritedDateSize,NULL))??
- ????{??
- ????????printf("寫文件失敗:%d/n",GetLastError());??
- ????}??
- ????else??
- ????{??
- ????????printf("寫文件成功,寫入%d字節(jié)。/n",dwWritedDateSize);??
- ????}??
- ????CloseHandle(hFileWrite);??
- ????return?0;??
- }??
- ??
- /*?************************************?
- *?int?main(void)?
- *?功能????演示使用SaveDataToFile和ReadFileContent函數(shù)?
- **************************************/??
- int?main(void)??
- {??
- ????LPSTR?szFileData?=?"這是一個(gè)例子";??
- ????SaveDataToFile("C://show.txt",szFileData,lstrlen(szFileData));??
- ????ReadFileContent("C://show.txt");??
- ????return?0;??
- }??
/* ************************************ *《精通Windows API》 * 示例代碼 * wr.c * 4.3.2 創(chuàng)建、打開、讀寫文件,獲取文件大小 **************************************/ /* 頭文件 */ #include <windows.h> #include <stdio.h> /* ************************************ * DWORD ReadFileContent(LPSTR szFilePath) * 功能 獲取文件大小 * 讀取文件內(nèi)容,并以16進(jìn)制的形式打印出來 * 參數(shù) LPSTR szFilePath * 文件路徑 **************************************/ DWORD ReadFileContent(LPSTR szFilePath) { //文件大小 HANDLE hFileRead; //保存文件大小 LARGE_INTEGER liFileSize; //成功讀取的文件數(shù)據(jù)大小 DWORD dwReadedSize; //累加計(jì)算已經(jīng)讀取數(shù)據(jù)的大小 LONGLONG liTotalRead = 0; //文件數(shù)據(jù)緩存 BYTE lpFileDataBuffer[32]; //打開已經(jīng)存在的文件,讀取內(nèi)容。 hFileRead = CreateFile(szFilePath,// 要打開的文件名 GENERIC_READ, // 以讀方式打開 FILE_SHARE_READ, // 可共享讀 NULL, // 默認(rèn)安全設(shè)置 OPEN_EXISTING, // 只打開已經(jīng)存在的文件 FILE_ATTRIBUTE_NORMAL, // 常規(guī)文件屬性 NULL); // 無模板 //打開文件是否成功。 if(hFileRead==INVALID_HANDLE_VALUE) { printf("打開文件失敗:%d",GetLastError()); } if(!GetFileSizeEx(hFileRead,&liFileSize)) { printf("獲取文件大小失敗:%d",GetLastError()); } else { printf("文件大小為:%d/n",liFileSize.QuadPart); } //循環(huán)讀取并打印文件內(nèi)容 while(TRUE) { DWORD i; if(!ReadFile(hFileRead, //讀文件的句柄 lpFileDataBuffer, //存儲(chǔ)讀取的文件內(nèi)容 32, //讀的大小(字節(jié)) &dwReadedSize, //實(shí)際讀取的大小 NULL)) //不使用Overlapped { printf("讀文件錯(cuò)誤:%d/n",GetLastError()); break; } printf("讀取了%d字節(jié),文件內(nèi)容是:",dwReadedSize); for(i=0; i<dwReadedSize; i++) { printf("0x%x ",lpFileDataBuffer[i]); } printf("/n"); liTotalRead += dwReadedSize; if(liTotalRead == liFileSize.QuadPart) { printf("讀文件結(jié)束/n"); break; } } CloseHandle(hFileRead); return 0; } /* ************************************ * SaveDataToFile * 功能 將數(shù)據(jù)存儲(chǔ)到文件末尾 * 參數(shù) LPSTR szFilePath 文件路徑 * LPVOID lpData 需存儲(chǔ)的數(shù)據(jù) * DWORD dwDataSize 數(shù)據(jù)大小(字節(jié)) **************************************/ DWORD SaveDataToFile( LPSTR szFilePath, LPVOID lpData, DWORD dwDataSize) { //文件句柄 HANDLE hFileWrite; //成功寫入的數(shù)據(jù)大小 DWORD dwWritedDateSize; //打開已經(jīng)存在的文件,讀取內(nèi)容。 hFileWrite = CreateFile(szFilePath, // 要打開的文件名 GENERIC_WRITE, // 以寫方式打開 0, // 可共享讀 NULL, // 默認(rèn)安全設(shè)置 OPEN_ALWAYS, // 打開已經(jīng)存在的文件,沒用則創(chuàng)建 FILE_ATTRIBUTE_NORMAL, // 常規(guī)文件屬性 NULL); // 無模板 //判斷是否打開成功 if(hFileWrite==INVALID_HANDLE_VALUE) { printf("打開文件失敗:%d/n",GetLastError()); } //設(shè)置文件指針到文件尾 SetFilePointer(hFileWrite,0,0,FILE_END); //將數(shù)據(jù)寫入文件 if(!WriteFile(hFileWrite,lpData,dwDataSize,&dwWritedDateSize,NULL)) { printf("寫文件失敗:%d/n",GetLastError()); } else { printf("寫文件成功,寫入%d字節(jié)。/n",dwWritedDateSize); } CloseHandle(hFileWrite); return 0; } /* ************************************ * int main(void) * 功能 演示使用SaveDataToFile和ReadFileContent函數(shù) **************************************/ int main(void) { LPSTR szFileData = "這是一個(gè)例子"; SaveDataToFile("C://show.txt",szFileData,lstrlen(szFileData)); ReadFileContent("C://show.txt"); return 0; }
?
?
?
?
4.3.2 創(chuàng)建、打開、讀寫文件,獲取文件大小
在Windows系統(tǒng)中,創(chuàng)建和打開文件都是使用API函數(shù)CreateFile,CreateFile通過指定不同的參數(shù)來表示是新建一個(gè)文件,打開已經(jīng)存在的文件,還是重新建立文件等。讀寫文件最為直接的方式是使用ReadFile和WriteFile函數(shù),也可以使用文件鏡像,獲取文件大小一般使用GetFileSize函數(shù),也可以使用GetFileAttributesEx等函數(shù)(在4.3.7節(jié)介紹)。讀寫文件、獲取文件大小之前都需要使用CreateFile創(chuàng)建或打開的文件,獲得文件句柄。
在文件操作中,文件句柄是一個(gè)關(guān)鍵的概念。文件句柄惟一標(biāo)識(shí)了一個(gè)文件,ReadFile、
WriteFile、GetFileSize等函數(shù)是使用文件句柄作為參數(shù)來表示,用戶需要讀、寫、獲取大小的文件是哪一個(gè)文件。在對(duì)文件進(jìn)行操作前,都必須要使用CreateFile獲得文件句柄。
?
1.關(guān)鍵API
(1)CreateFile
CreateFile是文件操作中最主要的一個(gè)函數(shù)。幾乎所有的文件操作都需要使用到文件句柄。而CreateFile函數(shù)為這些操作建立文件句柄。CreateFile函數(shù)定義如下:
(2)ReadFile。
ReadFile動(dòng)能是從文件中讀出數(shù)據(jù)。需要使用CreateFile所返回的文件句柄。函數(shù)原型如下:
(3)WriteFile。
WriteFile函數(shù)的功能是將數(shù)據(jù)寫入到文件中,寫入到文件指針?biāo)诘奈恢?#xff0c;寫入操作完成后,文件指針會(huì)移動(dòng)到寫入的數(shù)據(jù)之后,函數(shù)原型如下:
(4)GetFileSize、GetFileSizeEX.
GetFileSize、GetFileSizeEX的功能是一致的,都是獲取文件大小,函數(shù)原型分別如下。
/* ************************************ *《精通Windows API》 * 示例代碼 * files.c * 4.3.1 刪除、復(fù)制、重命名、移動(dòng)文件 **************************************/ /* 頭文件 */ #include <windows.h> #include <stdio.h> /* ************************************ * int main( int argc, PCHAR argv[] ) * 功能 應(yīng)用程序主函數(shù),根據(jù)輸入?yún)?shù) * 刪除、復(fù)制、重命名文件 * * 參數(shù) 刪除文件: * -d 文件路徑 * 將文件路徑1的文件復(fù)制到文件路徑2: * -c 文件路徑1 文件路徑2 * 將文件路徑1的文件移動(dòng)、重命名為文件路徑2的文件 * -m 文件路徑1 文件路徑2 **************************************/ int main(int argc, PCHAR argv[]) { LPSTR y="c:/2.bat"; LPSTR x="c:/1.bat"; //-d參數(shù),刪除文件。 if(0==lstrcmp("-d",argv[1]) && argc==3) { if(!DeleteFile(argv[2])) { printf("刪除文件錯(cuò)誤:%x/n",GetLastError()); } else { printf("刪除成功!/n"); } } //-c參數(shù),復(fù)制文件。 //如果文件存在,詢問用戶是否覆蓋 else if(0==lstrcmp("-c",argv[1]) && argc==4) { //復(fù)制,不覆蓋已經(jīng)存在的文件 if(!CopyFile(argv[2],argv[3],TRUE)) { //LastError == 0x50,文件存在。 if(GetLastError() == 0x50) { printf("文件%s已經(jīng)存在,是否覆蓋?y/n:",argv[3]); if('y'==getchar()) { //復(fù)制,覆蓋已經(jīng)存在的文件。 if(!CopyFile(argv[2],argv[3],FALSE)) { printf("復(fù)制文件錯(cuò)誤,%d/n",GetLastError()); } else { printf("復(fù)制成功!/n"); } } else { return 0; } } } else { printf("復(fù)制成功!/n"); } } //-m參數(shù),移動(dòng)、重命名文件。 else if(0==lstrcmp("-m",argv[1]) && argc==4) { if(!MoveFile( x,y)) { printf("移動(dòng)文件錯(cuò)誤:%d/n",GetLastError()); } else { printf("移動(dòng)文件成功!/n"); } } else { printf("參數(shù)錯(cuò)誤!/n"); } }
?4.3.3 創(chuàng)建目錄
編程實(shí)現(xiàn)創(chuàng)建目錄是非常簡(jiǎn)單的,只要使用API函數(shù)CreateDirectory即可。
1. 關(guān)鍵API
(1) Createdirectory
函數(shù)原型如下:
◇參數(shù)
lpPathName:輸入?yún)?shù),所要?jiǎng)?chuàng)建的目錄名或路徑。
lpSecurityAttributes:輸入?yún)?shù),設(shè)置為NULL。
◇返回值
返回BOOL值,表示是否成功。
◇使用說明
如果程序返回失敗,可以使用GetLastError函數(shù)獲取錯(cuò)誤信息。可能的值包括ERROR
ALREADY EXISTS(文件夾已經(jīng)存在)和ERROR PATH NOT FOUND(路徑不存在)。
/* ************************************ *《精通Windows API》 * 示例代碼 * dir.c * 4.3.3 創(chuàng)建目錄 **************************************/ /* 頭文件 */ #include <windows.h> #include <stdio.h> /* ************************************ * int main(void) * 功能 演示使用CreateDirectory創(chuàng)建目錄 **************************************/ int main(void) { //在程序的當(dāng)前目錄下創(chuàng)建“sub_dir”子目錄 LPSTR szDirPath = "sub_dir"; if (!CreateDirectory(szDirPath, NULL)) { printf("創(chuàng)建目錄 %s 錯(cuò)誤。/n",szDirPath); return 1; } //在C盤下創(chuàng)建目錄“example_dir” szDirPath = "C://example_dir"; if (!CreateDirectory(szDirPath, NULL)) { printf("創(chuàng)建目錄 %s 錯(cuò)誤。/n",szDirPath); return 1; } printf("成功/n"); return 0; }
?
?
?4.3.4 獲取程序所在的目錄、程序模塊路徑,獲取和設(shè)置當(dāng)前目錄
Windows系統(tǒng)提供一組API實(shí)現(xiàn)對(duì)程序運(yùn)行時(shí)相關(guān)目錄的獲取和設(shè)置。用戶可以使用
GetCurrentDirectory和SetCurrentDirectory獲取程序的當(dāng)前目錄,獲取模塊的路徑使用
GetModuleFileName,如果以NULL參數(shù)調(diào)用GetModuleFileName,將會(huì)返回當(dāng)前模塊的路徑。如果在程序主模塊(exe)中獲取當(dāng)前模塊路徑,便可以從當(dāng)前模塊的路徑中提取出程序運(yùn)行時(shí)所在的路徑。
1.關(guān)鍵API
(1)GetCurrentDirectory。
獲取進(jìn)程的當(dāng)前目錄,函數(shù)原型如下:
?(2)SetCurrentDirectory。
設(shè)置進(jìn)程的當(dāng)前目錄,函數(shù)原型如下:
(3)GetModuleFileName。
獲取模塊文件名,當(dāng)?shù)谝粋€(gè)參數(shù)為NULL時(shí)獲取當(dāng)前模塊路徑,函數(shù)原型如下:
/* ************************************ *《精通Windows API》 * 示例代碼 * cur_mod_dir.c * 4.3.4 獲取當(dāng)前目錄、獲取程序所在的目錄、獲取模塊路徑 **************************************/ /* 頭文件 */ #include <windows.h> #include <stdio.h> /* ************************************ * int main(void) * 功能 演示使用設(shè)置獲取當(dāng)前路徑 * 演示獲取模塊路徑 **************************************/ int main(void) { //用于存儲(chǔ)當(dāng)前路徑 CHAR szCurrentDirectory[MAX_PATH]; //用于存儲(chǔ)模塊路徑 CHAR szMoudlePath[MAX_PATH]; //Kernel32文件名與句柄 LPSTR szKernel32 = "kernel32.dll"; HMODULE hKernel32; //當(dāng)前路徑的長(zhǎng)度,也用于判斷獲取是否成功 DWORD dwCurDirPathLen; //獲取進(jìn)程當(dāng)前目錄 dwCurDirPathLen = GetCurrentDirectory(MAX_PATH,szCurrentDirectory); if(dwCurDirPathLen == 0) { printf("獲取當(dāng)前目錄錯(cuò)誤。/n"); return 0; } printf("進(jìn)程當(dāng)前目錄為 %s /n",szCurrentDirectory); //將進(jìn)程當(dāng)前目錄設(shè)置為“C:/” lstrcpy(szCurrentDirectory, "C://"); if(!SetCurrentDirectory(szCurrentDirectory)) { printf("設(shè)置當(dāng)前目錄錯(cuò)誤。/n"); return 0; } printf("已經(jīng)設(shè)置當(dāng)前目錄為 %s /n",szCurrentDirectory); //在當(dāng)前目錄下創(chuàng)建子目錄“current_dir” //運(yùn)行完成后C:盤下將出現(xiàn)文件夾“current_dir” CreateDirectory("current_dir", NULL); //再次獲取系統(tǒng)當(dāng)前目錄 dwCurDirPathLen = GetCurrentDirectory(MAX_PATH,szCurrentDirectory); if(dwCurDirPathLen == 0) { printf("獲取當(dāng)前目錄錯(cuò)誤。/n"); return 0; } printf("GetCurrentDirectory獲取當(dāng)前目錄為 %s /n", szCurrentDirectory); //使用NULL參數(shù),獲取本模塊的路徑。 if(!GetModuleFileName(NULL,szMoudlePath,MAX_PATH)) { printf("獲取模塊路徑錄錯(cuò)誤。/n"); return 0; } printf("本模塊路徑 %s /n",szMoudlePath); //獲取Kernel32.dll的模塊句柄。 hKernel32 = LoadLibrary(szKernel32); //使用Kernel32.dll的模塊句柄,獲取其路徑。 if(!GetModuleFileName(hKernel32,szMoudlePath,MAX_PATH)) { printf("獲取模塊路徑錯(cuò)誤。/n"); return 0; } printf("kernel32模塊路徑 %s /n",szMoudlePath); return 0; }
?
?
?
?
4.3.5 查找文件、遍歷指定目錄下的文件和子目錄
Windows API中,有一組專門的函數(shù)和結(jié)構(gòu),用于遍歷目錄,它們是FindFirstFile函數(shù)、
FindNextFile函數(shù)和WIN32_FIND_DATA結(jié)構(gòu)。使用FindFirstFile和FindNextFile函數(shù)并與do-while循環(huán)結(jié)合,可以完成遍歷目錄的任務(wù),詳見實(shí)例4-10。
值得一提的是,FindFirstFile輸入?yún)?shù)的路徑需使用通配符,也就是用戶可以根據(jù)一些條件來對(duì)查找的文件作簡(jiǎn)單的過濾。實(shí)例4-10講解查找特定目錄下的所有文件和文件夾。讀者可根據(jù)自己的需要,指定查找文件的條件。
1.關(guān)鍵API
(1)FindFirstFile。
查找第一個(gè)目錄或文件,獲取查找句柄,函數(shù)原型如下:
(2)FindNextFile
對(duì)文件、文件夾進(jìn)行循環(huán)查找,函數(shù)原型如下:
2.關(guān)鍵結(jié)構(gòu)
WIN32_FIND_DATA結(jié)構(gòu)用于表示找到的文件,結(jié)構(gòu)中包括文件、目錄的名字,創(chuàng)建、最后訪問和最后寫入時(shí)間,文件大小、文件屬性等。
/* ************************************ *《精通Windows API》 * 示例代碼 * sub_dir.c * 4.3.5 遍歷目錄下的文件和子目錄 **************************************/ /* 頭文件 */ #include <windows.h> #include <stdio.h> /* ************************************ * DWORD EnumerateFileInDrectory(LPSTR szPath) * 功能 遍歷目錄下的文件和子目錄,將顯示文件的 * 文件和文件夾隱藏、加密的屬性 * 參數(shù) LPTSTR szPath,為需遍歷的路徑 * 返回值 0代表執(zhí)行完成,1代碼發(fā)生錯(cuò)誤 **************************************/ DWORD EnumerateFileInDrectory(LPSTR szPath) { WIN32_FIND_DATA FindFileData; HANDLE hListFile; CHAR szFilePath[MAX_PATH]; //構(gòu)造代表子目錄和文件夾路徑的字符串,使用通配符“*” lstrcpy(szFilePath, szPath); //注釋的代碼可以用于查找所有以“.txt結(jié)尾”的文件。 //lstrcat(szFilePath, "//*.txt"); lstrcat(szFilePath, "//*"); //查找第一個(gè)文件/目錄,獲得查找句柄 hListFile = FindFirstFile(szFilePath,&FindFileData); //判斷句柄 if(hListFile==INVALID_HANDLE_VALUE) { printf("錯(cuò)誤:%d",GetLastError()); return 1; } else { do { /* 如果不想顯示代表本級(jí)目錄和上級(jí)目錄的“.”和“..”, 可以使用注釋部分的代碼過濾。 if(lstrcmp(FindFileData.cFileName,TEXT("."))==0|| lstrcmp(FindFileData.cFileName,TEXT(".."))==0) { continue; } */ //打印文件名、目錄名 printf("%s/t/t",FindFileData.cFileName); //判斷文件屬性,加密文件或文件夾 if(FindFileData.dwFileAttributes&FILE_ATTRIBUTE_ENCRYPTED) { printf("<加密> "); } //判斷文件屬性,隱藏文件或文件夾 if(FindFileData.dwFileAttributes&FILE_ATTRIBUTE_HIDDEN) { printf("<隱藏> "); } //判斷文件屬性,目錄 if(FindFileData.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) { printf("<DIR> "); } //讀者可根據(jù)文件屬性表中的內(nèi)容自行添加判斷文件屬性。 printf("/n"); } while(FindNextFile(hListFile, &FindFileData)); } return 0; } /* ************************************ * int main(int argc, PCHAR argv[]) * 功能 調(diào)用ListFileInDrectory * 遍歷目錄下的文件和子目錄 * 參數(shù) argv[1]為需遍歷的路徑,如果為空則獲取 * 當(dāng)前路徑 **************************************/ int main(int argc, PCHAR argv[]) { if(argc == 2) { EnumerateFileInDrectory(argv[1]); } else { CHAR szCurrentPath[MAX_PATH]; GetCurrentDirectory(MAX_PATH,szCurrentPath); EnumerateFileInDrectory(szCurrentPath); } return 0; }
?
?4.3.6 遞歸遍歷目錄樹
?
在實(shí)例4-10的基礎(chǔ)上稍加改造,進(jìn)行循環(huán)遞歸調(diào)用,采用樹形結(jié)構(gòu)深度遍歷的方法。可以遍歷指定目錄中的所有文件、包括子目錄中的文件。代碼實(shí)現(xiàn)如實(shí)例4-11所示。
[cpp] view plaincopyprint?/* ************************************ *《精通Windows API》 * 示例代碼 * tree.c * 4.3.6 遞歸遍歷目錄樹 * 2007年10月 **************************************/ /* 頭文件 */ #include <windows.h> #include <stdio.h> /* 預(yù)處理申明 */ #pragma comment (lib, "User32.lib") /* 函數(shù)申明 */ DWORD ListAllFileInDrectory(LPSTR szPath); /* 全局變量 */ //記錄所有的文件和目錄數(shù) DWORD dwTotalFileNum = 0; /* ************************************ * DWORD ListAllFileInDrectory(LPSTR szPath) * 功能 遍歷目錄及所有子目錄,打印路徑 * * 參數(shù) LPTSTR szPath,為需遍歷的目錄 * * 返回值 0代表執(zhí)行完成,1代碼發(fā)生錯(cuò)誤 **************************************/ DWORD ListAllFileInDrectory(LPSTR szPath) { CHAR szFilePath[MAX_PATH]; WIN32_FIND_DATA FindFileData; HANDLE hListFile; CHAR szFullPath[MAX_PATH]; //構(gòu)造代表子目錄和文件夾路徑的字符串,使用通配符“*” lstrcpy(szFilePath, szPath); lstrcat(szFilePath, "//*"); //查找第一個(gè)文件/目錄,獲得查找句柄 hListFile = FindFirstFile(szFilePath,&FindFileData); if(hListFile==INVALID_HANDLE_VALUE) { printf("錯(cuò)誤:%d",GetLastError()); return 1; } else { do { // 過濾“.”和“..”,不需要遍歷 if(lstrcmp(FindFileData.cFileName,TEXT("."))==0|| lstrcmp(FindFileData.cFileName,TEXT(".."))==0) { continue; } //構(gòu)造成全路徑 wsprintf(szFullPath,"%s//%s", szPath,FindFileData.cFileName); dwTotalFileNum++; //打印 printf("/n%d/t%s/t",dwTotalFileNum,szFullPath); //如果是目錄,則遞歸調(diào)用,列舉下級(jí)目錄 if(FindFileData.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) { printf("<DIR>"); ListAllFileInDrectory(szFullPath); } } while(FindNextFile(hListFile, &FindFileData)); } return 0; } /* ************************************ * int main(int argc, PCHAR argv[]) * 功能 調(diào)用ListAllFileInDrectory * 遍歷目錄下的文件和子目錄 * * 參數(shù) argv[1]為需遍歷的路徑,如果為空則獲取 * 當(dāng)前路徑 * * 2007年10月 * **************************************/ int main(int argc, PCHAR argv[]) { if(argc == 2) { ListAllFileInDrectory(argv[1]); } else { CHAR szCurrentPath[MAX_PATH]; GetCurrentDirectory(MAX_PATH,szCurrentPath); ListAllFileInDrectory(szCurrentPath); } return 0; }
?
?
?
4.3.7 獲取、設(shè)置文件屬性和時(shí)間
為了獲取文件屬性,用戶可以使用GetFileAttributes與GetFileAttributesEx函數(shù)。
GetFileAttributesEx函數(shù)除了返回文件屬性外,還返回文件時(shí)間信息、文件大小等。
GetFileAttributesEx將返回結(jié)果保存在WIN32_FILE_ATTRIBUTE DATA結(jié)構(gòu)中。
獲取的文件時(shí)間是以FILETIME格式存在的,如果要正確顯示,還需要對(duì)其時(shí)區(qū)進(jìn)行調(diào)整,調(diào)整為本地時(shí)區(qū),然后轉(zhuǎn)換為系統(tǒng)時(shí)間格式,便于顯示。
前面在獲取文件大小時(shí)已經(jīng)介紹,NTFS文件系統(tǒng)使用了64位數(shù)據(jù)來表示文件大小。因?yàn)?2位的數(shù)據(jù)最多只能表示4GB的大小。Windows將其分為了高32位和低32位,兩個(gè)都需要使用到,這一點(diǎn)尤其要在對(duì)大于4GB的文件操作時(shí)注意。
1.關(guān)鍵API
(1)GetFileAttributeS。
獲取文件或目錄的屬牲-函數(shù)原型如下:
(2)GetFileAttributesEx。
獲取文件或目錄的屬性、時(shí)間、大小,以WIN32_FILE ATTRIBUTE_DATA結(jié)構(gòu)的形式返回
結(jié)果,函數(shù)原型如下:
(3) SetFileAttributes.
設(shè)置文件或目錄的屬性,函數(shù)原型如下:
(4)FileTimeToLocalFileTime。
把文件時(shí)間轉(zhuǎn)換為本地的文件時(shí)間,函數(shù)原型如下:
5)FileTimeToSystemTime
將文件時(shí)間轉(zhuǎn)換為系統(tǒng)時(shí)間(SYSTEMTIME格式),便于顯示,函數(shù)原型如下:
2.關(guān)鍵數(shù)據(jù)結(jié)構(gòu)
(1) FILETIM。
此結(jié)構(gòu)用最小的數(shù)據(jù)量表示的時(shí)間,但是不便于用戶查看和顯示。通過API獲取的系統(tǒng)時(shí)間都是這種格式的。如果要使用顯示,可以使用FileTimeToSystemTime轉(zhuǎn)換為便于顯示的SYSTEMTIME結(jié)構(gòu)。
(2) SYSTEMTIME。
此結(jié)構(gòu)使用了較為直觀的方式表示時(shí)間。
(3) WIN32_FILE ATTRIBUTE_DATA。
GetFileAttributesEx使用這個(gè)結(jié)構(gòu)表示返回結(jié)果,包括文件屬性、文件創(chuàng)建時(shí)間、文件最后訪問時(shí)間、文件最后寫入時(shí)間和文件大小。
- #include?<windows.h> ??
- #include?<stdio.h> ??
- ??
- /*?函數(shù)申明 */??
- DWORD?ShowFileTime(PFILETIME?lptime);??
- DWORD?ShowFileSize(DWORD?dwFileSizeHigh,DWORD?dwFileSizeLow);??
- DWORD?ShowFileAttrInfo(DWORD?dwAttribute);??
- DWORD?SetFileHiddenAndReadonly(LPSTR?szFileName);??
- ??
- /*?************************************?
- ?*?DWORD?ShowFileAttributes(LPSTR?szPath)?
- ?*?功能???獲取并顯示文件屬性,?
- ?*??????調(diào)用ShowFileTime、ShowFileSize和?
- ?*??????ShowFileAttrInfo函數(shù)?
- ?*?
- ?*?參數(shù)???LPTSTR?szPath,獲取并顯示此文件的屬性?
- ?*?
- ?*?返回值??0代表執(zhí)行完成,1代碼發(fā)生錯(cuò)誤?
- ?**************************************/??
- DWORD?ShowFileAttributes(LPSTR?szPath)??
- {??
- ????//文件屬性結(jié)構(gòu) ??
- ????WIN32_FILE_ATTRIBUTE_DATA?wfad;??
- ????printf("文件:%s/n",szPath);??
- ????//獲取文件屬性 ??
- ????if(!GetFileAttributesEx(szPath,??
- ????????GetFileExInfoStandard,??
- ????????&wfad))??
- ????{??
- ????????printf("獲取文件屬性錯(cuò)誤:%d/n",GetLastError());??
- ????????return?1;??
- ????}??
- ????//顯示相關(guān)時(shí)間 ??
- ????printf("創(chuàng)建時(shí)間:/t");??
- ????ShowFileTime(&(wfad.ftCreationTime));??
- ????printf("最后訪問時(shí)間:/t");??
- ????ShowFileTime(&(wfad.ftLastAccessTime));??
- ????printf("最后修改時(shí)間:/t");??
- ????ShowFileTime(&(wfad.ftLastWriteTime));??
- ????//顯示文件大小 ??
- ????ShowFileSize(wfad.nFileSizeHigh,wfad.nFileSizeLow);??
- ????//顯示文件屬性 ??
- ????ShowFileAttrInfo(wfad.dwFileAttributes);??
- ??
- ????return?0;??
- }??
- ??
- /*?************************************?
- ?*?DWORD?ShowFileAttrInfo(DWORD?dwAttribute)?
- ?*?功能???打印將文件屬性?
- ?*?
- ?*?參數(shù)???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("<系統(tǒng)文件>?");??
- ????if(dwAttribute&FILE_ATTRIBUTE_TEMPORARY)??
- ????????printf("<臨時(shí)文件>?");??
- ??
- ????printf("/n");??
- ??
- ????return?0;??
- }??
- /*?************************************?
- ?*?DWORD?ShowFileSize(DWORD?dwFileSizeHigh,?DWORD?dwFileSizeLow)?
- ?*?功能???打印文件大小信息?
- ?*?
- ?*?參數(shù)???DWORD?dwFileSizeHigh,文件大小高32位?
- ?*??????DWORD?dwFileSizeLow,文件大小低32位?
- ?*?
- ?*?返回值?0?
- ?**************************************/??
- DWORD?ShowFileSize(DWORD?dwFileSizeHigh,?DWORD?dwFileSizeLow)??
- {??
- ????ULONGLONG?liFileSize;??
- ????liFileSize?=?dwFileSizeHigh;??
- ??
- ????//高們移動(dòng)32位 ??
- ????liFileSize?<<=?sizeof(DWORD)*8;??
- ????liFileSize?+=?dwFileSizeLow;??
- ????printf("文件大小:/t%I64u?字節(jié)/n",liFileSize);??
- ????return?0;??
- }??
- ??
- /*?************************************?
- ?*DWORD?ShowFileTime(PFILETIME?lptime)?
- ?*?功能???輪換文件時(shí)間,將打印?
- ?*?
- ?*?參數(shù)???PFILETIME?lptime,指向文件時(shí)間的指針?
- ?*?
- ?*?返回值?0?
- ?**************************************/??
- DWORD?ShowFileTime(PFILETIME?lptime)??
- {??
- ????//文件時(shí)間結(jié)構(gòu) ??
- ????FILETIME?ftLocal;??
- ????//系統(tǒng)時(shí)間結(jié)構(gòu) ??
- ????SYSTEMTIME?st;??
- ????//調(diào)整為系統(tǒng)所在時(shí)區(qū)的時(shí)間 ??
- ????FileTimeToLocalFileTime(??
- ????????lptime,??
- ????????&ftLocal??
- ????????);??
- ????//將文件時(shí)間轉(zhuǎn)換為SYSTEMTIME格式,便于顯示。 ??
- ????FileTimeToSystemTime(??
- ????????&ftLocal,??
- ????????&st??
- ????????);??
- ????//顯示時(shí)間信息字符串 ??
- ????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)?
- ?*?功能???將指定的文件設(shè)置為隱藏和只讀?
- ?*?
- ?*?參數(shù)???LPSTR?szFileName,文件路徑?
- ?*?
- ?*?返回值?0?
- ?**************************************/??
- DWORD?SetFileHiddenAndReadonly(LPSTR?szFileName)??
- {??
- ????//獲取原來的文件屬性 ??
- ????DWORD?dwFileAttributes?=?GetFileAttributes(szFileName);??
- ????//將只讀和隱藏屬性附加到原來的文件屬性上 ??
- ????dwFileAttributes?|=?FILE_ATTRIBUTE_READONLY;??
- ????dwFileAttributes?|=?FILE_ATTRIBUTE_HIDDEN;??
- ????//設(shè)置文件屬性,并判斷是否成功。 ??
- ????if(SetFileAttributes(szFileName,?dwFileAttributes))??
- ????{??
- ????????printf("文件%s的隱藏和屬性設(shè)置成功/n",szFileName);??
- ????}??
- ????else??
- ????{??
- ????????printf("屬性設(shè)置;?%d/n",GetLastError());??
- ????}??
- ????return?0;??
- }??
- ??
- /*?************************************?
- ?*?int?main(int?argc,?PCHAR?argv[])?
- ?*?功能???設(shè)置和獲取文件屬性等?
- ?*?
- ?*?參數(shù)???顯示第一個(gè)參數(shù)指定文件的屬性、時(shí)間、大小?
- ?*??????將第二個(gè)參數(shù)的屬性設(shè)置為隱藏、只讀。?
- ?*?
- ?*?返回值??0代表執(zhí)行完成,1代碼發(fā)生錯(cuò)誤?
- ?**************************************/??
- int?main(int?argc,?PCHAR?argv[])??
- {?????
- ????if(argc?!=?3)??
- ????{??
- ????????printf("請(qǐng)輸入?yún)?shù)/n");??
- ????????printf("顯示第一個(gè)參數(shù)指定文件的屬性、時(shí)間、大小;/n");??
- ????????printf("將第二個(gè)參數(shù)的屬性設(shè)置為隱藏、只讀。");??
- ????????return?1;??
- ????}??
- ????ShowFileAttributes(argv[1]);??
- ????SetFileHiddenAndReadonly(argv[2]);??
- ????return?0;??
- }??
/* ************************************ *《精通Windows API》 * 示例代碼 * attr.c * 4.3.7 獲取、設(shè)置文件屬性和時(shí)間 **************************************/ /* 頭文件 */ #include <windows.h> #include <stdio.h> /* 函數(shù)申明 */ DWORD ShowFileTime(PFILETIME lptime); DWORD ShowFileSize(DWORD dwFileSizeHigh,DWORD dwFileSizeLow); DWORD ShowFileAttrInfo(DWORD dwAttribute); DWORD SetFileHiddenAndReadonly(LPSTR szFileName); /* ************************************ * DWORD ShowFileAttributes(LPSTR szPath) * 功能 獲取并顯示文件屬性, * 調(diào)用ShowFileTime、ShowFileSize和 * ShowFileAttrInfo函數(shù) * * 參數(shù) LPTSTR szPath,獲取并顯示此文件的屬性 * * 返回值 0代表執(zhí)行完成,1代碼發(fā)生錯(cuò)誤 **************************************/ DWORD ShowFileAttributes(LPSTR szPath) { //文件屬性結(jié)構(gòu) WIN32_FILE_ATTRIBUTE_DATA wfad; printf("文件:%s/n",szPath); //獲取文件屬性 if(!GetFileAttributesEx(szPath, GetFileExInfoStandard, &wfad)) { printf("獲取文件屬性錯(cuò)誤:%d/n",GetLastError()); return 1; } //顯示相關(guān)時(shí)間 printf("創(chuàng)建時(shí)間:/t"); ShowFileTime(&(wfad.ftCreationTime)); printf("最后訪問時(shí)間:/t"); ShowFileTime(&(wfad.ftLastAccessTime)); printf("最后修改時(shí)間:/t"); ShowFileTime(&(wfad.ftLastWriteTime)); //顯示文件大小 ShowFileSize(wfad.nFileSizeHigh,wfad.nFileSizeLow); //顯示文件屬性 ShowFileAttrInfo(wfad.dwFileAttributes); return 0; } /* ************************************ * DWORD ShowFileAttrInfo(DWORD dwAttribute) * 功能 打印將文件屬性 * * 參數(shù) 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("<系統(tǒng)文件> "); if(dwAttribute&FILE_ATTRIBUTE_TEMPORARY) printf("<臨時(shí)文件> "); printf("/n"); return 0; } /* ************************************ * DWORD ShowFileSize(DWORD dwFileSizeHigh, DWORD dwFileSizeLow) * 功能 打印文件大小信息 * * 參數(shù) DWORD dwFileSizeHigh,文件大小高32位 * DWORD dwFileSizeLow,文件大小低32位 * * 返回值 0 **************************************/ DWORD ShowFileSize(DWORD dwFileSizeHigh, DWORD dwFileSizeLow) { ULONGLONG liFileSize; liFileSize = dwFileSizeHigh; //高們移動(dòng)32位 liFileSize <<= sizeof(DWORD)*8; liFileSize += dwFileSizeLow; printf("文件大小:/t%I64u 字節(jié)/n",liFileSize); return 0; } /* ************************************ *DWORD ShowFileTime(PFILETIME lptime) * 功能 輪換文件時(shí)間,將打印 * * 參數(shù) PFILETIME lptime,指向文件時(shí)間的指針 * * 返回值 0 **************************************/ DWORD ShowFileTime(PFILETIME lptime) { //文件時(shí)間結(jié)構(gòu) FILETIME ftLocal; //系統(tǒng)時(shí)間結(jié)構(gòu) SYSTEMTIME st; //調(diào)整為系統(tǒng)所在時(shí)區(qū)的時(shí)間 FileTimeToLocalFileTime( lptime, &ftLocal ); //將文件時(shí)間轉(zhuǎn)換為SYSTEMTIME格式,便于顯示。 FileTimeToSystemTime( &ftLocal, &st ); //顯示時(shí)間信息字符串 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) * 功能 將指定的文件設(shè)置為隱藏和只讀 * * 參數(shù) LPSTR szFileName,文件路徑 * * 返回值 0 **************************************/ DWORD SetFileHiddenAndReadonly(LPSTR szFileName) { //獲取原來的文件屬性 DWORD dwFileAttributes = GetFileAttributes(szFileName); //將只讀和隱藏屬性附加到原來的文件屬性上 dwFileAttributes |= FILE_ATTRIBUTE_READONLY; dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN; //設(shè)置文件屬性,并判斷是否成功。 if(SetFileAttributes(szFileName, dwFileAttributes)) { printf("文件%s的隱藏和屬性設(shè)置成功/n",szFileName); } else { printf("屬性設(shè)置; %d/n",GetLastError()); } return 0; } /* ************************************ * int main(int argc, PCHAR argv[]) * 功能 設(shè)置和獲取文件屬性等 * * 參數(shù) 顯示第一個(gè)參數(shù)指定文件的屬性、時(shí)間、大小 * 將第二個(gè)參數(shù)的屬性設(shè)置為隱藏、只讀。 * * 返回值 0代表執(zhí)行完成,1代碼發(fā)生錯(cuò)誤 **************************************/ int main(int argc, PCHAR argv[]) { if(argc != 3) { printf("請(qǐng)輸入?yún)?shù)/n"); printf("顯示第一個(gè)參數(shù)指定文件的屬性、時(shí)間、大小;/n"); printf("將第二個(gè)參數(shù)的屬性設(shè)置為隱藏、只讀。"); return 1; } ShowFileAttributes(argv[1]); SetFileHiddenAndReadonly(argv[2]); return 0; }
?
?
?
?
?
?
?
?
?
?4.4 內(nèi)存映射文件
本節(jié)介紹Mapping File、文件句柄等較高級(jí)操作。本節(jié)將通過以下幾個(gè)實(shí)例來講解高級(jí)文件系統(tǒng)操作的API。
◇ 使用Mapping File提高文件讀寫的效率。
◇通過Mapping File在進(jìn)程間共享內(nèi)存。
◇通過文件句柄獲得文件路徑。
4.4.1 使用Mapping File提高文件讀寫的效率
文件映射( mapping)是一種在將文件內(nèi)容映射到進(jìn)程的虛擬地址空間的技術(shù)。視圖(View)是一段虛擬地址空間,進(jìn)程可以通過View來存取文件的內(nèi)容,視圖是一段內(nèi)存,可以使用指針來操作視圖。使用的文件映射之后,讀寫文件就如同對(duì)讀寫內(nèi)存一樣簡(jiǎn)單。在使用文件映射時(shí)需要?jiǎng)?chuàng)建映射對(duì)象,映射對(duì)象分為命名的和未命名的。映射對(duì)象還存取權(quán)限。
使用文件映射至少有3個(gè)好處,一是因?yàn)槲募谴鎯?chǔ)于硬盤上的,而文件視圖是一段內(nèi)存,使用文件映射操作時(shí)更方便;二是效率更高;三是可以在不同的進(jìn)程間共享數(shù)據(jù)。
文件映射依賴于系統(tǒng)虛擬內(nèi)存管理的分頁(yè)機(jī)制。
本節(jié)將演示如何使用文件映射,下一節(jié)將演示如何使用文件映射來進(jìn)行內(nèi)存共享。
1. 關(guān)鍵API
(1)GetSystemInfo
獲取系統(tǒng)信息,在實(shí)例 4-14中用于獲取系統(tǒng)內(nèi)存分配粒度。有關(guān)內(nèi)存分配粒度的概念參見第5章和虛擬內(nèi)存管理相關(guān)章節(jié)。
(2)CreateFileMapping。
創(chuàng)建mapping對(duì)象,函數(shù)原型如下
(3)MapViewOfFile。
創(chuàng)建視圖,將文件mapping映射到當(dāng)前進(jìn)程內(nèi)存虛擬地址空間。函數(shù)原型如下:
?(4)FlushViewOfFile。
將視圖中的文件數(shù)據(jù)寫入到磁盤上。調(diào)用此參數(shù)后,對(duì)映射視圖的內(nèi)存操作將會(huì)及時(shí)反映到硬件中的文件。函數(shù)原型如下:
◇使用說明
如果不調(diào)用此函數(shù),數(shù)據(jù)最終也會(huì)寫回到硬盤,調(diào)用此函數(shù)后,數(shù)據(jù)會(huì)立刻寫回到硬盤。
(5) FillMemory、CopyMemory。內(nèi)存操作函數(shù),分別為填充內(nèi)存和復(fù)制內(nèi)存,詳見第5章
?
[cpp] view plaincopyprint?/* ************************************ *《精通Windows API》 * 示例代碼 * file_map.c * 4.4.1 使用Mapping File提高文件讀寫的效率 **************************************/ /* 頭文件 */ #include <windows.h> #include <stdio.h> /* 預(yù)處理申明 */ #define BUFFSIZE 1024 // 內(nèi)存大小 #define FILE_MAP_START 0x28804 // 文件映射的起始的位置 /* 全局變量 */ LPTSTR lpcTheFile = TEXT("test.dat"); // 文件名 /* ************************************ * int main(void) * 功能 演示使用文件mapping * * 參數(shù) 無 * * 返回值 0代表執(zhí)行完成,1代表發(fā)生錯(cuò)誤 **************************************/ int main(void) { HANDLE hMapFile; // 文件內(nèi)存映射區(qū)域的句柄 HANDLE hFile; // 文件的句柄 DWORD dBytesWritten; // 寫入的字節(jié)數(shù) DWORD dwFileSize; // 文件大小 DWORD dwFileMapSize; // 文件映射的大小 DWORD dwMapViewSize; // 視圖(View)的大小 DWORD dwFileMapStart; // 文件映射視圖的起始位置 DWORD dwSysGran; // 系統(tǒng)內(nèi)存分配的粒度 SYSTEM_INFO SysInfo; // 系統(tǒng)信息 LPVOID lpMapAddress; // 內(nèi)在映射區(qū)域的起始位置 PCHAR pData; // 數(shù)據(jù) INT i; // 循環(huán)變量 INT iData; INT iViewDelta; BYTE cMapBuffer[32]; // 存儲(chǔ)從mapping中計(jì)出的數(shù)據(jù) // 創(chuàng)建一個(gè)文件 hFile = CreateFile(lpcTheFile, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); //判斷文件是否創(chuàng)建成功 if (hFile == INVALID_HANDLE_VALUE) { printf("CreateFile error/n",GetLastError); return 1; } // 依次寫入整數(shù),一共寫入65535個(gè)整數(shù) // 在32位平臺(tái)下,大小為65535*32 for (i=0; i<65535; i++) { WriteFile (hFile, &i, sizeof (i), &dBytesWritten, NULL); } // 查看寫入完成后的文件大小 dwFileSize = GetFileSize(hFile, NULL); printf("文件大小: %d/n", dwFileSize); //獲取系統(tǒng)信息,內(nèi)存分配粒度 //獲取分配粒度,進(jìn)行下面的幾個(gè)計(jì)算, //目的是為了映射的數(shù)據(jù)與系統(tǒng)內(nèi)存分配粒度對(duì)齊,提高內(nèi)存訪問效率 GetSystemInfo(&SysInfo); dwSysGran = SysInfo.dwAllocationGranularity; //計(jì)算mapping的起始位置 dwFileMapStart = (FILE_MAP_START / dwSysGran) * dwSysGran; // 計(jì)算mapping view的大小 dwMapViewSize = (FILE_MAP_START % dwSysGran) + BUFFSIZE; // 計(jì)算mapping的大小 dwFileMapSize = FILE_MAP_START + BUFFSIZE; // 計(jì)算需要讀取的數(shù)據(jù)的偏移 iViewDelta = FILE_MAP_START - dwFileMapStart; // 創(chuàng)建File mapping hMapFile = CreateFileMapping( hFile, // 需要映射的文件的句柄 NULL, // 安全選項(xiàng):默認(rèn) PAGE_READWRITE, // 可讀,可寫 0, // mapping對(duì)象的大小,高位 dwFileMapSize, // mapping對(duì)象的大小,低位 NULL); // mapping對(duì)象的名字 if (hMapFile == NULL) { printf("CreateFileMapping error: %d/n", GetLastError() ); return 1; } // 映射view lpMapAddress = MapViewOfFile(hMapFile, // mapping對(duì)象的句柄 FILE_MAP_ALL_ACCESS, // 可讀,可寫 0, // 映射的文件偏移,高32位 dwFileMapStart, // 映射的文件偏移,低32位 dwMapViewSize); // 映射到View的數(shù)據(jù)大小 if (lpMapAddress == NULL) { printf("MapViewOfFile error: %d/n", GetLastError()); return 1; } printf ("文件map view相對(duì)于文件的起始位置: 0x%x/n", dwFileMapStart); printf ("文件map view的大小:0x%x/n", dwMapViewSize); printf ("文件mapping對(duì)象的大小:0x%x/n", dwFileMapSize); printf ("從相對(duì)于map view 0x%x 字節(jié)的位置讀取數(shù)據(jù),", iViewDelta); // 將指向數(shù)據(jù)的指針偏移,到達(dá)我們關(guān)心的地方 pData = (PCHAR) lpMapAddress + iViewDelta; // 讀取數(shù)據(jù),賦值給變量 iData = *(PINT)pData; // 顯示讀取的數(shù)據(jù) printf ("為:0x%.8x/n", iData); // 從mapping中復(fù)制數(shù)據(jù),32個(gè)字節(jié),并打印 CopyMemory(cMapBuffer,lpMapAddress,32); printf("lpMapAddress起始的32字節(jié)是:"); for(i=0; i<32; i++) { printf("0x%.2x ",cMapBuffer[i]); } // 將mapping的前32個(gè)字節(jié)用0xff填充 FillMemory(lpMapAddress,32,(BYTE)0xff); // 將映射的數(shù)據(jù)寫回到硬盤上 FlushViewOfFile(lpMapAddress,dwMapViewSize); printf("/n已經(jīng)將lpMapAddress開始的32字節(jié)使用0xff填充。/n"); // 關(guān)閉mapping對(duì)象 if(!CloseHandle(hMapFile)) { printf("/nclosing the mapping object error %d!", GetLastError()); } //關(guān)閉文件 if(!CloseHandle(hFile)) { printf("/nError %ld occurred closing the file!", GetLastError()); } return 0; }
?
4.4.2 通過Mapping File在進(jìn)程間傳遞和共享數(shù)據(jù)
進(jìn)程間通信、共享數(shù)據(jù)有很多種方法,文件映射是常用的一種方法。因?yàn)閙apping對(duì)象
系統(tǒng)中是全局的,一個(gè)進(jìn)程創(chuàng)建的Mapping對(duì)象可以從另外一個(gè)進(jìn)程中打開,映射視圖就
進(jìn)程間共享的內(nèi)存了。一般在共享的內(nèi)存數(shù)據(jù)量比較大時(shí),選擇使用文件映射進(jìn)行共享。
1.關(guān)鍵API
(1)OpenFileMapping。
打開已經(jīng)存在的文件映射,函數(shù)原型如下:
(2) UnmapViewO伍ile。
取消文件映射,函數(shù)原型如下:
/* ************************************ *《精通Windows API》 * 示例代碼 * pro_s1.c * 4.4.2 通過Mapping File在進(jìn)程間共享內(nèi)存 **************************************/ /* 頭文件 */ #include <windows.h> #include <stdio.h> #include <conio.h> /* 預(yù)處理申明 */ #define BUF_SIZE 256 /* 全局變量 */ LPTSTR szName = TEXT("SharedFileMappingObject"); LPTSTR szMsg = TEXT("進(jìn)程的消息"); /* ************************************ * int main(void) * 功能 演示文件mapping共享內(nèi)存,寫入數(shù)據(jù)到共享內(nèi)存 * * 參數(shù) 無 * * 返回值 0代表執(zhí)行完成,代表發(fā)生錯(cuò)誤 **************************************/ void main(int argc, PCHAR argv[]) { //文件映射句柄 HANDLE hMapFile; //共享數(shù)據(jù)緩沖區(qū)指針 LPTSTR pBuf; //創(chuàng)建命名的文件映射,不代表任務(wù)硬盤上的文件 hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, BUF_SIZE, szName); if (hMapFile == NULL || hMapFile == INVALID_HANDLE_VALUE) { printf("CreateFileMapping error: %d/n", GetLastError()); return; } //創(chuàng)建View pBuf = (LPTSTR) MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, BUF_SIZE); if (pBuf == NULL) { printf("MapViewOfFile error %d/n", GetLastError()); return; } //將共享數(shù)據(jù)復(fù)制到文件映射中,如果運(yùn)行時(shí)輸入了參數(shù)則使用參數(shù) if(argc==1) { CopyMemory((PVOID)pBuf, szMsg, strlen(szMsg)); } else { DWORD dwCopyLen = (lstrlen(argv[1])<BUF_SIZE) ? lstrlen(argv[1]): BUF_SIZE; CopyMemory((PVOID)pBuf, argv[1], dwCopyLen); } printf("運(yùn)行程序,完成運(yùn)行后,按任意鍵退出。"); _getch(); //取消映射,退出 UnmapViewOfFile(pBuf); CloseHandle(hMapFile); }
?
.實(shí)例4-15讀取并顯示共享數(shù)據(jù)
本實(shí)例代碼從實(shí)例4-14共享的Mapping對(duì)象中讀取數(shù)據(jù),并將數(shù)據(jù)顯示出來。實(shí)例4-14與實(shí)例4-15是兩個(gè)進(jìn)程,實(shí)現(xiàn)了進(jìn)程間數(shù)據(jù)的共享。這兩個(gè)進(jìn)程可以通過各自的指針,對(duì)同一段內(nèi)存進(jìn)行讀寫。
本實(shí)例先打開指定對(duì)象名的Mapping對(duì)象(與實(shí)例4-14中使用的CreateFileMapping創(chuàng)建的Mapping對(duì)象需有一樣的對(duì)象名),然后創(chuàng)建視圖,從視圖中讀取數(shù)據(jù)。
/* ************************************ *《精通Windows API》 * 示例代碼 * pro_s2.c * 4.4.2 通過Mapping File在進(jìn)程間共享內(nèi)存 **************************************/ #include <windows.h> #include <stdio.h> #include <conio.h> /* 預(yù)處理申明*/ #pragma comment (lib, "User32.lib") #define BUF_SIZE 256 /* 全局變量 */ TCHAR szName[]=TEXT("SharedFileMappingObject"); /* ************************************ * int main(void) * 功能 演示文件mapping共享內(nèi)存,從共享數(shù)據(jù)中讀信息 * * 參數(shù) 無 * * 返回值 0代表執(zhí)行完成,代表發(fā)生錯(cuò)誤 **************************************/ void main() { HANDLE hMapFile; LPTSTR pBuf; //打開文件mapping hMapFile = OpenFileMapping( FILE_MAP_ALL_ACCESS, FALSE, szName); if (hMapFile == NULL) { printf("OpenFileMapping error: %d./n", GetLastError()); return; } //映射 pBuf = MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, BUF_SIZE); if (pBuf == NULL) { printf("MapViewOfFile error %d/n", GetLastError()); return; } //消息得到的共享數(shù)據(jù) MessageBox(NULL, pBuf, TEXT("Process2"), MB_OK); //取消mapping,關(guān)閉句柄,返回 UnmapViewOfFile(pBuf); CloseHandle(hMapFile); }
?
?
?
?
?
4.4.3 通過文件句柄獲得文件路徑
Windows系統(tǒng)提供了一個(gè)名為GetMappedFileName的API函數(shù),這個(gè)函數(shù)可以實(shí)現(xiàn)從
mapping對(duì)象的句柄得到被映射文件的路徑。但是路徑是以設(shè)備名的形式給出的,如類似于
“/Device/HarddiskVolume3/1.TXT”的形式。
將設(shè)備名轉(zhuǎn)換為路徑名需要使用到一個(gè)API函數(shù)-QueryDosDevice,這個(gè)函數(shù)可以將驅(qū)動(dòng)器的根路徑轉(zhuǎn)換為設(shè)備名,然后進(jìn)行循環(huán)比較,可得文件路徑。
1.關(guān)鍵API
(1)GetMappedFileName。
從映射對(duì)象獲取被映射文件的文件設(shè)備名,函數(shù)原型如下:
(2)QueryDosDevice
獲取MS_DOS設(shè)備名,函數(shù)原型如下:
◇返回值返回DWORD值,如果成功,則返回值為lpTargetPath指向字符串的長(zhǎng)度,如果失敗為0。
2.實(shí)例4-16通過文件句柄獲取文件路徑
GetFileNameFromHandle通過參數(shù)輸入的句柄創(chuàng)建mapping對(duì)象,然后調(diào)用GetMapped
FileName函數(shù),獲得對(duì)象所映射的文件的設(shè)備名,然后使用QueryDosDevice函數(shù)循環(huán)判斷
驅(qū)動(dòng)器設(shè)備名與路徑的關(guān)系,在找到正確的驅(qū)動(dòng)器路徑后,構(gòu)造好文件路徑并輸出。
/* ************************************ *《精通Windows API》 * 示例代碼 * handle_path.cpp * 4.4.3 通過文件句柄獲取文件路徑 **************************************/ /* 頭文件*/ #include <windows.h> #include <stdio.h> #include <tchar.h> #include <string.h> #include <psapi.h> /* 預(yù)處理申明*/ #pragma comment (lib, "Psapi.lib") #define BUFSIZE 512 /* 函數(shù)申明*/ BOOL GetFileNameFromHandle(HANDLE hFile) ; /* ************************************ * BOOL GetFileNameFromHandle(HANDLE hFile) * 功能 從文件句柄獲取文件路徑 * * 參數(shù) ANDLE hFile,需要獲得路徑的文件句柄 * * 返回值BOOL 是否成功。 **************************************/ BOOL GetFileNameFromHandle(HANDLE hFile) { TCHAR pszFilename[MAX_PATH+1]; HANDLE hFileMap; PVOID pMem; // 獲得文件大小,并決斷是否為 DWORD dwFileSizeHigh = 0; DWORD dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh); if( dwFileSizeLow == 0 && dwFileSizeHigh == 0 ) { printf("不能map文件大小為的文件./n"); return FALSE; } // 創(chuàng)建mapping對(duì)象 hFileMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 1, NULL); if (!hFileMap) { printf("CreateFileMapping error: %d",GetLastError()); return FALSE; } pMem = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 1); if (!pMem) { printf("MapViewOfFile error: %d",GetLastError()); return FALSE; } // 從mapping對(duì)象獲得文件名 if (0 == GetMappedFileName (GetCurrentProcess(), pMem, pszFilename, MAX_PATH)) { printf("GetMappedFileName error: %d",GetLastError()); return FALSE; } // 將設(shè)備名轉(zhuǎn)換為路徑 TCHAR szTemp[BUFSIZE] = {0}; if (0 == GetLogicalDriveStrings(BUFSIZE-1, szTemp)) { printf("GetLogicalDriveStrings error: %d",GetLastError()); return FALSE; } TCHAR szName[MAX_PATH]; TCHAR szDrive[3] = {0}; BOOL bFound = FALSE; PTCHAR p = szTemp; do { CopyMemory(szDrive,p,2*sizeof(TCHAR)); // 通過路徑查找設(shè)備名 if (!QueryDosDevice(szDrive, szName, BUFSIZE)) { printf("QueryDosDevice error: %d",GetLastError()); return FALSE; } UINT uNameLen = lstrlen(szName); if (uNameLen < MAX_PATH) { //比較驅(qū)動(dòng)器的設(shè)備名與文件設(shè)備名是否匹配 bFound = strncmp(pszFilename, szName,uNameLen) == 0; if (bFound) { //如果匹配,說明已經(jīng)找到,構(gòu)造路徑。 TCHAR szTempFile[MAX_PATH]; wsprintf(szTempFile, TEXT("%s%s"), szDrive, pszFilename+uNameLen); lstrcpy(pszFilename, szTempFile); } } // 循環(huán)到下一個(gè)NULL while (*p++); } while (!bFound && *p); UnmapViewOfFile(pMem); CloseHandle(hFileMap); printf("File path is %s/n", pszFilename); return TRUE; } /* ************************************ * int main() * 功能 查找第一個(gè)目錄中第一個(gè)txt文件 * 打開文件,并根據(jù)文件句柄獲得文件路徑。 * * 參數(shù) 未使用 * * 返回值0表示成功,表示失敗。 **************************************/ int main() { HANDLE hFile; HANDLE hFind; WIN32_FIND_DATA wfd; hFind = FindFirstFile("*.txt",&wfd); if(hFind == INVALID_HANDLE_VALUE) { printf("can not find a file"); return 1; } //CloseHandle(hFind); printf("find %s at current dir/n",wfd.cFileName); hFile = CreateFile(wfd.cFileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(hFile == INVALID_HANDLE_VALUE) { printf("create file error, %d",GetLastError()); } else { GetFileNameFromHandle(hFile) ; } CloseHandle(hFile); return 0; }
?
?
轉(zhuǎn)載于:https://www.cnblogs.com/xiaogui9527/p/3269067.html
總結(jié)
以上是生活随笔為你收集整理的《精通Windows API-函数、接口、编程实例》——第4章文件系统的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: oracle pl/sql 中目录的创建
- 下一篇: java信息管理系统总结_java实现科