第4章文件系統編程
4.2 磁盤和驅動器管理windows
文件系統的基本概念:
包括磁盤分區,卷,目錄,文件對象,文件句柄,文件映射
1.磁盤分區:
物理磁盤,邏輯磁盤
2.卷:
也稱邏輯驅動器,是NTFS,FAT32等文件系統組織結構的最高層.
卷是存儲設備(硬盤)上由文件系統管理的一塊區域,在邏輯上相互隔離的存儲單元.api
windows命名規則:
主文件名+擴展名
windows中文件系統的長度被限制爲260個字符.
這260個字符包括卷標,路徑,主文件名和擴展名,分隔符緩存
在DOS下的保留設備名不能作文件名或主文件名.如CON,PRN,AUX,NUL,COM1.....安全
=================================================================網絡
磁盤和驅動器管理API
GetLogicalDrivers 獲取主機中全部的邏輯驅動器,以Bit Map的形式返回.
GetLogicalDriverString 獲取主機中全部的邏輯驅動器,以驅動器根路徑字符串返回.
FindFirstVolume 查找主機中的第一個驅動器,返回查找句柄.
FindNextVolume 根據FindFirstVolume返回句柄,查找主機中後繼的邏輯驅動器
FindVolumeClose 關閉驅動器查找句柄
GetDriveType 獲取驅動器類型
GetVolumeInformation 獲取邏輯驅動器信息
FindFirstVolumeMountPoint 查找指定卷的第一個掛載點,返回查找句柄
FindNextVolumeMountPoint 根據FindFirstVolumeMountPoint返回的句柄,查找卷的後繼掛載點.
FindVolumeMountPointClose 關閉掛載點查找句柄
GetVolumeNameForVolumeMountPoint 根據指定掛載點獲取相應的卷設備名
SetVolumeMountPoint 將指定卷掛載到指定掛載點處
GetDiskFreeSpace 獲取磁盤空間信息,包括每簇的扇區數,每扇區的字節數,簇數量,空閒的簇數量
GetDiskFreeSpaceEx 獲取用戶可用的空閒空間的字節數,磁盤總容量的字節數數據結構
文件和目錄管理API
DeleteFile 刪除參數所指定文件
CopyFile 複製指定文件爲一個新文件
MoveFile 將指定文件或目錄移動到指定位置
CreateFile 新建或打開一個文件,獲取文件句柄
ReadFile 讀取由文件句柄指定文件的內容
WriteFile 向由文件句柄指定的文件中寫入內容
GetFileSize 獲取文件大小,返回DWORD中;大小超出DWORD最大值時可指定高32位的DWORD聯合存儲
GetFileSizeEx 獲取文件大小,存儲到一個64位的大整數聯合體中.
CreateDirectory 建立一個目錄
GetCurrentDirectory 獲取當前程序所在目錄
SetCurrentDirectory 設置當前程序所在目錄
GetModuleFileName 獲取當前模塊全路徑
FindFirstFile 查找指定目錄下第一個文件句柄或目錄,得到查找句柄
FindNextFile 根據FindFirstFile得到的句柄,循環查找文件或目錄
GetFileAttributes 獲取指定文件目錄屬性,返回一個DWORD值
GetFileAttributesEx 獲取文件或目錄屬性,存儲在WIN32_FILE_ATTRIBUTE_DATA結構體中
SetFileAttributes 將文件屬性設定爲指定值
FileTimeToLocalFileTime 將文件時間轉換爲本地時間
FileTimeToSystemTime 將文件轉換爲系統時間,SYSTEMTIME格式便於顯示app
高級文件操做
CreateFileMapping 建立文件的映射對象
MapViewOfFile 建立視圖,將建立的文件映射對象映射到當前進程的地址空間中
FlushViewOfFile 將視圖中的數據都寫入磁盤,對視圖的操做都會反映到磁盤上的文件中
OpenFileMapping 打開已經存在的命名的文件映射對象
UnmapViewOfFile 取消文件映射
GetMappedFileName 從映射對象獲取被映射文件的文件設備名
QueryDosDevice 獲取MS-DOS設備名函數
=================================================================學習
2 磁盤和驅動器管理
◇使用兩種方法來遍歷驅動器並獲取驅動器屬性。
◇使用API操做驅動器掛載點。
◇判斷光驅中是否有光盤。
◇獲取磁盤剩餘空間、扇區信息等。
4.2.1 遍歷卷並獲取屬性
用到的API函數:
(1) GetLogicalDrives。
獲取主機中全部的邏輯驅動器,以BitMap的形式返回,其函數原型以下:
(2) GetLogicalDriverStrings。
獲取主機中全部驅動器,以驅動器根路徑字符串返回,其函數原型以下:
(3)FindFirstVolume。
查找主機中的第一個驅動器,返回驅動器設備名,其函數原型以下:
(4)FindNextVolume
查找主機中後繼的邏輯驅動器,其函數原型以下:
(5)FindVo1umeClose。
\關閉FindFirstVolume打開的卷遍歷句柄,其函數原型以下:
(6) GetDriveType。
獲取驅動器類型,其函數原型以下:
(7) GetVolumeInformation。
獲取邏輯驅動器信息,其函數原型以下:

-
-
-
-
-
-
-
-
- #include <windows.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
-
- #define BUFSIZE 1024
-
- BOOL GetDirverInfo(LPSTR szDrive);
-
-
-
-
-
- void main(void)
- {
- CHAR szLogicalDriveStrings[BUFSIZE];
- PCHAR szDrive;
-
- ZeroMemory(szLogicalDriveStrings,BUFSIZE);
-
- GetLogicalDriveStrings(BUFSIZE - 1,szLogicalDriveStrings);
- szDrive = (PCHAR)szLogicalDriveStrings;
-
- do
- {
- if(!GetDirverInfo(szDrive))
- {
- printf("/nGet Volume Information Error: %d", GetLastError());
- }
-
-
-
- szDrive += (lstrlen(szDrive)+1);
- }
- while(*szDrive!='/x00');
- }
-
-
-
-
-
-
-
-
- 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. 可移動磁盤 ");
- 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. 網絡磁盤 ");
- break;
- case DRIVE_CDROM:
- printf("The drive is a CD-ROM drive. 光驅 ");
- 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 存儲驅動器序列號%u",dwVolumeSerialNumber);
- printf ("/nMaximum Component Length is 文件系統所支持的文件組成部分的最大值%u",dwMaximumComponentLength);
- printf ("/nSystem Type is文件系統類 %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");
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- printf(".../n");
- return TRUE;
- }
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
將指定卷掛載到指定掛載點處,函數原型以下:
-
-
-
-
-
-
-
- #define _WIN32_WINNT 0x0501
- #include <windows.h>
- #include <stdio.h>
- #include <tchar.h>
- #define BUFSIZE MAX_PATH
- #define FILESYSNAMEBUFSIZE MAX_PATH
-
-
-
-
-
- BOOL ProcessVolumeMountPoint (HANDLE hPt,
- TCHAR *PtBuf, DWORD dwPtBufSize,
- TCHAR *Buf)
- {
- BOOL bFlag;
- TCHAR Path[BUFSIZE];
- TCHAR Target[BUFSIZE];
-
- 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);
- }
-
-
-
-
- BOOL ProcessVolume (HANDLE hVol, TCHAR *Buf, DWORD iBufSize)
- {
- BOOL bFlag;
- HANDLE hPt;
- TCHAR PtBuf[BUFSIZE];
- DWORD dwSysFlags;
- TCHAR FileSysNameBuf[FILESYSNAMEBUFSIZE];
-
- printf ("Volume found is /"%s/"./n", Buf);
-
-
- 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
- {
-
- hPt = FindFirstVolumeMountPoint(
- Buf,
- PtBuf,
- BUFSIZE
- );
-
- if (hPt == INVALID_HANDLE_VALUE)
- {
- printf ("/tNo volume mount points found!/n");
- }
- else
- {
-
- bFlag = ProcessVolumeMountPoint (hPt,
- PtBuf,
- BUFSIZE,
- Buf);
-
- while (bFlag)
- bFlag =
- ProcessVolumeMountPoint (hPt, PtBuf, BUFSIZE, Buf);
-
- FindVolumeMountPointClose(hPt);
- }
- }
-
-
- bFlag = FindNextVolume(
- hVol, Buf, iBufSize);
-
- return (bFlag);
- }
-
-
-
-
- int GetMountPoint(void)
- {
- TCHAR buf[BUFSIZE];
- HANDLE hVol;
- BOOL bFlag;
-
- 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)
- {
- printf( "/n/n/t%s, mount a volume at a mount point./n", argv );
- printf( "/tFor example, /"mount D:
- }
-
-
-
-
-
- int main( int argc, PCHAR argv[] )
- {
- BOOL bFlag;
- CHAR Buf[BUFSIZE];
-
- if( argc != 3 )
- {
- GetMountPoint();
- Usage( argv[0] );
- return( -1 );
- }
-
- bFlag = GetVolumeNameForVolumeMountPoint(
- argv[2],
- 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],
- 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 判斷光驅中是否有光盤
判斷光驅中是否有光盤,仍然可使用在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函數原型以下:
- * 4.2.3 判斷光驅中是否有光盤
- **************************************/
-
- #include <windows.h>
- #include <stdio.h>
- #include <tchar.h>
-
- #define BUFSIZE 512
-
-
-
-
-
-
-
-
-
- int main( int argc, PCHAR argv[] )
- {
-
- CHAR szFileSystemNameBuffer[BUFSIZE];
- DWORD dwLastError;
- DWORD dwFileSystemFlags;
-
-
- if( argc != 2 )
- {
- printf("請輸入驅動器的根路徑,好比: /"D:
- return( -1 );
- }
-
-
- if(GetDriveType(argv[1])!=DRIVE_CDROM)
- {
- printf("驅動器 %s 不是 CD/DVD ROM。/n",argv[1]);
- return( -1 );
- }
-
-
- if (!GetVolumeInformation(
- argv[1], NULL, 0,
- NULL,NULL,
- &dwFileSystemFlags,
- szFileSystemNameBuffer,
- BUFSIZE
- ))
- {
- dwLastError = GetLastError();
- if(dwLastError == 21)
- {
- printf("設備未就緒,請放入光盤!/n");
- return 0;
- }
- else
- {
- printf("GetVolumeInformation 錯誤 %d/n",dwLastError);
- return 0;
- }
- }
- printf ("光盤已經放入,文件系統類別 %s。/n",szFileSystemNameBuffer);
- return 0;
- }
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具備一樣的長度。
- #include <windows.h>
- #include <stdio.h>
-
-
-
-
-
-
-
- BOOL GetDiskSpaceInfo(LPCSTR pszDrive)
- {
- DWORD64 qwFreeBytesToCaller, qwTotalBytes, qwFreeBytes;
- DWORD dwSectPerClust, dwBytesPerSect, dwFreeClusters, dwTotalClusters;
- BOOL bResult;
-
-
- 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);
- }
-
-
- 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 (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文檔學習它們的使用方法。
- #include <windows.h>
- #include <stdio.h>
-
-
-
-
-
-
-
-
- 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))
- {
- 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;
- }
-
-
-
-
-
-
-
-
- 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)
- {
- 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的功能是一致的,都是獲取文件大小,函數原型分別以下。
-
-
-
-
-
-
-
-
- #include <windows.h>
- #include <stdio.h>
-
-
-
-
-
-
-
-
-
-
-
-
-
- int main(int argc, PCHAR argv[])
- {
- LPSTR y="c:/2.bat";
- LPSTR x="c:/1.bat";
-
- if(0==lstrcmp("-d",argv[1]) && argc==3)
- {
- if(!DeleteFile(argv[2]))
- {
- printf("刪除文件錯誤:%x/n",GetLastError());
- }
- else
- {
- printf("刪除成功!/n");
- }
- }
-
-
- else if(0==lstrcmp("-c",argv[1]) && argc==4)
- {
-
- if(!CopyFile(argv[2],argv[3],TRUE))
- {
-
- if(GetLastError() == 0x50)
- {
- printf("文件%s已經存在,是否覆蓋?y/n:",argv[3]);
- if('y'==getchar())
- {
-
- if(!CopyFile(argv[2],argv[3],FALSE))
- {
- printf("複製文件錯誤,%d/n",GetLastError());
- }
- else
- {
- printf("複製成功!/n");
- }
- }
- else
- {
- return 0;
- }
- }
- }
- else
- {
- printf("複製成功!/n");
- }
- }
-
- else if(0==lstrcmp("-m",argv[1]) && argc==4)
- {
- if(!MoveFile( x,y))
- {
- printf("移動文件錯誤:%d/n",GetLastError());
- }
- else
- {
- printf("移動文件成功!/n");
- }
- }
- else
- {
- printf("參數錯誤!/n");
- }
- }
4.3.3 建立目錄
編程實現建立目錄是很是簡單的,只要使用API函數CreateDirectory便可。
1. 關鍵API
(1) Createdirectory
函數原型以下:
◇參數
lpPathName:輸入參數,所要建立的目錄名或路徑。
lpSecurityAttributes:輸入參數,設置爲NULL。
◇返回值
返回BOOL值,表示是否成功。
◇使用說明
若是程序返回失敗,可使用GetLastError函數獲取錯誤信息。可能的值包括ERROR
ALREADY EXISTS(文件夾已經存在)和ERROR PATH NOT FOUND(路徑不存在)。
-
-
-
-
-
-
-
-
- #include <windows.h>
- #include <stdio.h>
-
-
-
-
-
- int main(void)
- {
-
- LPSTR szDirPath = "sub_dir";
- if (!CreateDirectory(szDirPath, NULL))
- {
- printf("建立目錄 %s 錯誤。/n",szDirPath);
- return 1;
- }
-
-
- szDirPath = "C://example_dir";
- if (!CreateDirectory(szDirPath, NULL))
- {
- printf("建立目錄 %s 錯誤。/n",szDirPath);
- return 1;
- }
- printf("成功/n");
-
- return 0;
- }
4.3.4 獲取程序所在的目錄、程序模塊路徑,獲取和設置當前目錄
Windows系統提供一組API實現對程序運行時相關目錄的獲取和設置。用戶可使用
GetCurrentDirectory和SetCurrentDirectory獲取程序的當前目錄,獲取模塊的路徑使用
GetModuleFileName,若是以NULL參數調用GetModuleFileName,將會返回當前模塊的路徑。若是在程序主模塊(exe)中獲取當前模塊路徑,即可以從當前模塊的路徑中提取出程序運行時所在的路徑。
1.關鍵API
(1)GetCurrentDirectory。
獲取進程的當前目錄,函數原型以下:
(2)SetCurrentDirectory。
設置進程的當前目錄,函數原型以下:
(3)GetModuleFileName。
獲取模塊文件名,當第一個參數爲NULL時獲取當前模塊路徑,函數原型以下:
-
-
-
-
-
-
-
-
- #include <windows.h>
- #include <stdio.h>
-
-
-
-
-
-
- int main(void)
- {
-
- CHAR szCurrentDirectory[MAX_PATH];
-
- CHAR szMoudlePath[MAX_PATH];
-
- LPSTR szKernel32 = "kernel32.dll";
- HMODULE hKernel32;
-
- DWORD dwCurDirPathLen;
-
-
- dwCurDirPathLen =
- GetCurrentDirectory(MAX_PATH,szCurrentDirectory);
- if(dwCurDirPathLen == 0)
- {
- printf("獲取當前目錄錯誤。/n");
- return 0;
- }
- printf("進程當前目錄爲 %s /n",szCurrentDirectory);
-
-
- lstrcpy(szCurrentDirectory, "C://");
- if(!SetCurrentDirectory(szCurrentDirectory))
- {
- printf("設置當前目錄錯誤。/n");
- return 0;
- }
- printf("已經設置當前目錄爲 %s /n",szCurrentDirectory);
-
-
-
- CreateDirectory("current_dir", NULL);
-
-
- dwCurDirPathLen =
- GetCurrentDirectory(MAX_PATH,szCurrentDirectory);
- if(dwCurDirPathLen == 0)
- {
- printf("獲取當前目錄錯誤。/n");
- return 0;
- }
- printf("GetCurrentDirectory獲取當前目錄爲 %s /n",
- szCurrentDirectory);
-
-
- if(!GetModuleFileName(NULL,szMoudlePath,MAX_PATH))
- {
- printf("獲取模塊路徑錄錯誤。/n");
- return 0;
- }
- printf("本模塊路徑 %s /n",szMoudlePath);
-
-
- hKernel32 = LoadLibrary(szKernel32);
-
-
- if(!GetModuleFileName(hKernel32,szMoudlePath,MAX_PATH))
- {
- printf("獲取模塊路徑錯誤。/n");
- return 0;
- }
- printf("kernel32模塊路徑 %s /n",szMoudlePath);
-
- return 0;
- }
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結構用於表示找到的文件,結構中包括文件、目錄的名字,建立、最後訪問和最後寫入時間,文件大小、文件屬性等。
-
-
-
-
-
-
-
-
- #include <windows.h>
- #include <stdio.h>
-
-
-
-
-
-
-
-
- DWORD EnumerateFileInDrectory(LPSTR szPath)
- {
- WIN32_FIND_DATA FindFileData;
- HANDLE hListFile;
- CHAR szFilePath[MAX_PATH];
-
-
- lstrcpy(szFilePath, szPath);
-
-
- lstrcat(szFilePath, "//*");
-
- hListFile = FindFirstFile(szFilePath,&FindFileData);
-
- if(hListFile==INVALID_HANDLE_VALUE)
- {
- printf("錯誤:%d",GetLastError());
- return 1;
- }
- else
- {
- do
- {
- /* 若是不想顯示錶明本級目錄和上級目錄的「.」和「..」,
- 可使用註釋部分的代碼過濾。
- 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> ");
- }
-
- printf("/n");
- }
- while(FindNextFile(hListFile, &FindFileData));
- }
- return 0;
- }
-
-
-
-
-
-
-
-
- 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 遞歸遍歷目錄樹
在實例4-10的基礎上稍加改造,進行循環遞歸調用,採用樹形結構深度遍歷的方法。能夠遍歷指定目錄中的全部文件、包括子目錄中的文件。代碼實現如實例4-11所示。
-
-
-
-
-
-
-
-
-
- #include <windows.h>
- #include <stdio.h>
-
-
- #pragma comment (lib, "User32.lib")
-
-
- DWORD ListAllFileInDrectory(LPSTR szPath);
-
-
-
- DWORD dwTotalFileNum = 0;
-
-
-
-
-
-
-
-
-
-
- DWORD ListAllFileInDrectory(LPSTR szPath)
- {
- CHAR szFilePath[MAX_PATH];
-
- WIN32_FIND_DATA FindFileData;
- HANDLE hListFile;
- CHAR szFullPath[MAX_PATH];
-
-
- lstrcpy(szFilePath, szPath);
- lstrcat(szFilePath, "//*");
-
- hListFile = FindFirstFile(szFilePath,&FindFileData);
-
- if(hListFile==INVALID_HANDLE_VALUE)
- {
- printf("錯誤:%d",GetLastError());
- return 1;
- }
- else
- {
- do
- {
-
- if(lstrcmp(FindFileData.cFileName,TEXT("."))==0||
- lstrcmp(FindFileData.cFileName,TEXT(".."))==0)
- {
- continue;
- }
-
- wsprintf(szFullPath,"%s//%s",
- szPath,FindFileData.cFileName);
- dwTotalFileNum++;
-
- printf("/n%d/t%s/t",dwTotalFileNum,szFullPath);
-
-
- if(FindFileData.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
- {
- printf("<DIR>");
- ListAllFileInDrectory(szFullPath);
- }
- }
- while(FindNextFile(hListFile, &FindFileData));
- }
- return 0;
- }
-
-
- /* ************************************
- * int main(int argc, PCHAR argv[])
- * 功能 調用ListAllFileInDrectory
- * 遍歷目錄下的文件和子目錄
- *
- * 參數 argv[1]爲需遍歷的路徑,若是爲空則獲取
- * 當前路徑
- *
- * 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 獲取、設置文件屬性和時間
爲了獲取文件屬性,用戶可使用GetFileAttributes與GetFileAttributesEx函數。
GetFileAttributesEx函數除了返回文件屬性外,還返回文件時間信息、文件大小等。
GetFileAttributesEx將返回結果保存在WIN32_FILE_ATTRIBUTE DATA結構中。
獲取的文件時間是以FILETIME格式存在的,若是要正確顯示,還須要對其時區進行調整,調整爲本地時區,而後轉換爲系統時間格式,便於顯示。
前面在獲取文件大小時已經介紹,NTFS文件系統使用了64位數據來表示文件大小。由於32位的數據最多隻能表示4GB的大小。Windows將其分爲了高32位和低32位,兩個都須要使用到,這一點尤爲要在對大於4GB的文件操做時注意。
1.關鍵API
(1)GetFileAttributeS。
獲取文件或目錄的屬牲-函數原型以下:
(2)GetFileAttributesEx。
獲取文件或目錄的屬性、時間、大小,以WIN32_FILE ATTRIBUTE_DATA結構的形式返回
結果,函數原型以下:
(3) SetFileAttributes.
設置文件或目錄的屬性,函數原型以下:
(4)FileTimeToLocalFileTime。
把文件時間轉換爲本地的文件時間,函數原型以下:
5)FileTimeToSystemTime
將文件時間轉換爲系統時間(SYSTEMTIME格式),便於顯示,函數原型以下:
2.關鍵數據結構
(1) FILETIM。
此結構用最小的數據量表示的時間,可是不便於用戶查看和顯示。經過API獲取的系統時間都是這種格式的。若是要使用顯示,可使用FileTimeToSystemTime轉換爲便於顯示的SYSTEMTIME結構。
(2) SYSTEMTIME。
此結構使用了較爲直觀的方式表示時間。
(3) WIN32_FILE ATTRIBUTE_DATA。
GetFileAttributesEx使用這個結構表示返回結果,包括文件屬性、文件建立時間、文件最後訪問時間、文件最後寫入時間和文件大小。
- #include <windows.h>
- #include <stdio.h>
-
-
- DWORD ShowFileTime(PFILETIME lptime);
- DWORD ShowFileSize(DWORD dwFileSizeHigh,DWORD dwFileSizeLow);
- DWORD ShowFileAttrInfo(DWORD dwAttribute);
- DWORD SetFileHiddenAndReadonly(LPSTR szFileName);
-
-
-
-
-
-
-
-
-
-
-
- DWORD ShowFileAttributes(LPSTR szPath)
- {
-
- WIN32_FILE_ATTRIBUTE_DATA wfad;
- printf("文件:%s/n",szPath);
-
- if(!GetFileAttributesEx(szPath,
- GetFileExInfoStandard,
- &wfad))
- {
- printf("獲取文件屬性錯誤:%d/n",GetLastError());
- return 1;
- }
-
- printf("建立時間:/t");
- ShowFileTime(&(wfad.ftCreationTime));
- printf("最後訪問時間:/t");
- ShowFileTime(&(wfad.ftLastAccessTime));
- printf("最後修改時間:/t");
- ShowFileTime(&(wfad.ftLastWriteTime));
-
- ShowFileSize(wfad.nFileSizeHigh,wfad.nFileSizeLow);
-
- ShowFileAttrInfo(wfad.dwFileAttributes);
-
- return 0;
- }
-
-
-
-
-
-
-
-
-
- DWORD ShowFileAttrInfo(DWORD dwAttribute)
- {
-
- printf("文件屬性:/t");
- if(dwAttribute&FILE_ATTRIBUTE_ARCHIVE)
- printf("<ARCHIVE> ");
- if(dwAttribute&FILE_ATTRIBUTE_COMPRESSED)
- printf("<壓縮> ");
- if(dwAttribute&FILE_ATTRIBUTE_DIRECTORY)
- printf("<目錄> ");
- if(dwAttribute&FILE_ATTRIBUTE_ENCRYPTED)
- printf("<加密> ");
- if(dwAttribute&FILE_ATTRIBUTE_HIDDEN)
- printf("<隱藏> ");
- if(dwAttribute&FILE_ATTRIBUTE_NORMAL)
- printf("<NORMAL> ");
- if(dwAttribute&FILE_ATTRIBUTE_OFFLINE)
- printf("<OFFLINE> ");
- if(dwAttribute&FILE_ATTRIBUTE_READONLY)
- printf("<只讀> ");
- if(dwAttribute&FILE_ATTRIBUTE_SPARSE_FILE)
- printf("<SPARSE> ");
- if(dwAttribute&FILE_ATTRIBUTE_SYSTEM)
- printf("<系統文件> ");
- if(dwAttribute&FILE_ATTRIBUTE_TEMPORARY)
- printf("<臨時文件> ");
-
- printf("/n");
-
- return 0;
- }
-
-
-
-
-
-
-
-
-
- DWORD ShowFileSize(DWORD dwFileSizeHigh, DWORD dwFileSizeLow)
- {
- ULONGLONG liFileSize;
- liFileSize = dwFileSizeHigh;
-
-
- liFileSize <<= sizeof(DWORD)*8;
- liFileSize += dwFileSizeLow;
- printf("文件大小:/t%I64u 字節/n",liFileSize);
- return 0;
- }
-
-
-
-
-
-
-
-
-
- DWORD ShowFileTime(PFILETIME lptime)
- {
-
- FILETIME ftLocal;
-
- SYSTEMTIME st;
-
- FileTimeToLocalFileTime(
- lptime,
- &ftLocal
- );
-
- FileTimeToSystemTime(
- &ftLocal,
- &st
- );
-
- printf("%4d年%.2d月%#02d日,%.2d:%.2d:%.2d/n",
- st.wYear,st.wMonth,st.wDay,st.wHour,st.wMinute,st.wSecond);
-
- return 0;
- }
-
-
-
-
-
-
-
-
-
- DWORD SetFileHiddenAndReadonly(LPSTR szFileName)
- {
-
- DWORD dwFileAttributes = GetFileAttributes(szFileName);
-
- dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
- dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
-
- if(SetFileAttributes(szFileName, dwFileAttributes))
- {
- printf("文件%s的隱藏和屬性設置成功/n",szFileName);
- }
- else
- {
- printf("屬性設置; %d/n",GetLastError());
- }
- return 0;
- }
-
-
-
-
-
-
-
-
-
-
- int main(int argc, PCHAR argv[])
- {
- if(argc != 3)
- {
- printf("請輸入參數/n");
- printf("顯示第一個參數指定文件的屬性、時間、大小;/n");
- printf("將第二個參數的屬性設置爲隱藏、只讀。");
- return 1;
- }
- ShowFileAttributes(argv[1]);
- SetFileHiddenAndReadonly(argv[2]);
- return 0;
- }

4.4 內存映射文件
本節介紹Mapping File、文件句柄等較高級操做。本節將經過如下幾個實例來說解高級文件系統操做的API。
◇ 使用Mapping File提升文件讀寫的效率。
◇經過Mapping File在進程間共享內存。
◇經過文件句柄得到文件路徑。
4.4.1 使用Mapping File提升文件讀寫的效率
文件映射( mapping)是一種在將文件內容映射到進程的虛擬地址空間的技術。視圖(View)是一段虛擬地址空間,進程能夠經過View來存取文件的內容,視圖是一段內存,可使用指針來操做視圖。使用的文件映射以後,讀寫文件就如同對讀寫內存同樣簡單。在使用文件映射時須要建立映射對象,映射對象分爲命名的和未命名的。映射對象還存取權限。
使用文件映射至少有3個好處,一是由於文件是存儲於硬盤上的,而文件視圖是一段內存,使用文件映射操做時更方便;二是效率更高;三是能夠在不一樣的進程間共享數據。
文件映射依賴於系統虛擬內存管理的分頁機制。
本節將演示如何使用文件映射,下一節將演示如何使用文件映射來進行內存共享。
1. 關鍵API
(1)GetSystemInfo
獲取系統信息,在實例 4-14中用於獲取系統內存分配粒度。有關內存分配粒度的概念參見第5章和虛擬內存管理相關章節。
(2)CreateFileMapping。
建立mapping對象,函數原型以下
(3)MapViewOfFile。
建立視圖,將文件mapping映射到當前進程內存虛擬地址空間。函數原型以下:
(4)FlushViewOfFile。
將視圖中的文件數據寫入到磁盤上。調用此參數後,對映射視圖的內存操做將會及時反映到硬件中的文件。函數原型以下:
◇使用說明
若是不調用此函數,數據最終也會寫回到硬盤,調用此函數後,數據會馬上寫回到硬盤。
(5) FillMemory、CopyMemory。內存操做函數,分別爲填充內存和複製內存,詳見第5章
-
-
-
-
-
-
-
-
- #include <windows.h>
- #include <stdio.h>
-
- #define BUFFSIZE 1024 // 內存大小
- #define FILE_MAP_START 0x28804 // 文件映射的起始的位置
-
- LPTSTR lpcTheFile = TEXT("test.dat");
-
-
-
-
-
-
-
-
-
- int main(void)
- {
- HANDLE hMapFile;
- HANDLE hFile;
- DWORD dBytesWritten;
- DWORD dwFileSize;
- DWORD dwFileMapSize;
- DWORD dwMapViewSize;
- DWORD dwFileMapStart;
- DWORD dwSysGran;
- SYSTEM_INFO SysInfo;
- LPVOID lpMapAddress;
- PCHAR pData;
- INT i;
- INT iData;
- INT iViewDelta;
- BYTE cMapBuffer[32];
-
-
- hFile = CreateFile(lpcTheFile,
- GENERIC_READ | GENERIC_WRITE,
- 0,
- NULL,
- CREATE_ALWAYS,
- FILE_ATTRIBUTE_NORMAL,
- NULL);
-
- if (hFile == INVALID_HANDLE_VALUE)
- {
- printf("CreateFile error/n",GetLastError);
- return 1;
- }
-
-
- for (i=0; i<65535; i++)
- {
- WriteFile (hFile, &i, sizeof (i), &dBytesWritten, NULL);
- }
-
- dwFileSize = GetFileSize(hFile, NULL);
- printf("文件大小: %d/n", dwFileSize);
-
-
-
-
- GetSystemInfo(&SysInfo);
- dwSysGran = SysInfo.dwAllocationGranularity;
-
-
- dwFileMapStart = (FILE_MAP_START / dwSysGran) * dwSysGran;
-
- dwMapViewSize = (FILE_MAP_START % dwSysGran) + BUFFSIZE;
-
- dwFileMapSize = FILE_MAP_START + BUFFSIZE;
-
- iViewDelta = FILE_MAP_START - dwFileMapStart;
-
-
- hMapFile = CreateFileMapping( hFile,
- NULL,
- PAGE_READWRITE,
- 0,
- dwFileMapSize,
- NULL);
- if (hMapFile == NULL)
- {
- printf("CreateFileMapping error: %d/n", GetLastError() );
- return 1;
- }
-
-
- lpMapAddress = MapViewOfFile(hMapFile,
- FILE_MAP_ALL_ACCESS,
- 0,
- dwFileMapStart,
- dwMapViewSize);
- if (lpMapAddress == NULL)
- {
- printf("MapViewOfFile error: %d/n", GetLastError());
- return 1;
- }
-
- printf ("文件map view相對於文件的起始位置: 0x%x/n",
- dwFileMapStart);
- printf ("文件map view的大小:0x%x/n", dwMapViewSize);
- printf ("文件mapping對象的大小:0x%x/n", dwFileMapSize);
- printf ("從相對於map view 0x%x 字節的位置讀取數據,", iViewDelta);
-
-
- pData = (PCHAR) lpMapAddress + iViewDelta;
-
- iData = *(PINT)pData;
-
- printf ("爲:0x%.8x/n", iData);
-
-
- CopyMemory(cMapBuffer,lpMapAddress,32);
- printf("lpMapAddress起始的32字節是:");
- for(i=0; i<32; i++)
- {
- printf("0x%.2x ",cMapBuffer[i]);
- }
-
- FillMemory(lpMapAddress,32,(BYTE)0xff);
-
- FlushViewOfFile(lpMapAddress,dwMapViewSize);
- printf("/n已經將lpMapAddress開始的32字節使用0xff填充。/n");
-
-
- if(!CloseHandle(hMapFile))
- {
- printf("/nclosing the mapping object error %d!",
- GetLastError());
- }
-
- if(!CloseHandle(hFile))
- {
- printf("/nError %ld occurred closing the file!",
- GetLastError());
- }
-
- return 0;
- }


4.4.2 經過Mapping File在進程間傳遞和共享數據
進程間通訊、共享數據有不少種方法,文件映射是經常使用的一種方法。由於mapping對象
系統中是全局的,一個進程建立的Mapping對象能夠從另一個進程中打開,映射視圖就
進程間共享的內存了。通常在共享的內存數據量比較大時,選擇使用文件映射進行共享。
1.關鍵API
(1)OpenFileMapping。
打開已經存在的文件映射,函數原型以下:
(2) UnmapViewO伍ile。
取消文件映射,函數原型以下:
-
-
-
-
-
-
-
- #include <windows.h>
- #include <stdio.h>
- #include <conio.h>
-
- #define BUF_SIZE 256
-
- LPTSTR szName = TEXT("SharedFileMappingObject");
- LPTSTR szMsg = TEXT("進程的消息");
-
-
-
-
-
-
-
-
-
- void main(int argc, PCHAR argv[])
- {
-
- HANDLE hMapFile;
-
- LPTSTR pBuf;
-
- 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;
- }
-
- pBuf = (LPTSTR) MapViewOfFile(hMapFile,
- FILE_MAP_ALL_ACCESS,
- 0,
- 0,
- BUF_SIZE);
- if (pBuf == NULL)
- {
- printf("MapViewOfFile error %d/n", GetLastError());
- return;
- }
-
- 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("運行程序,完成運行後,按任意鍵退出。");
- _getch();
-
- UnmapViewOfFile(pBuf);
- CloseHandle(hMapFile);
- }
.實例4-15讀取並顯示共享數據
本實例代碼從實例4-14共享的Mapping對象中讀取數據,並將數據顯示出來。實例4-14與實例4-15是兩個進程,實現了進程間數據的共享。這兩個進程能夠經過各自的指針,對同一段內存進行讀寫。
本實例先打開指定對象名的Mapping對象(與實例4-14中使用的CreateFileMapping建立的Mapping對象需有同樣的對象名),而後建立視圖,從視圖中讀取數據。
-
-
-
-
-
-
- #include <windows.h>
- #include <stdio.h>
- #include <conio.h>
-
- #pragma comment (lib, "User32.lib")
- #define BUF_SIZE 256
-
- TCHAR szName[]=TEXT("SharedFileMappingObject");
-
-
-
-
-
-
-
-
-
- void main()
- {
- HANDLE hMapFile;
- LPTSTR pBuf;
-
- 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;
- }
-
- MessageBox(NULL, pBuf, TEXT("Process2"), MB_OK);
-
- UnmapViewOfFile(pBuf);
- CloseHandle(hMapFile);
- }
4.4.3 經過文件句柄得到文件路徑
Windows系統提供了一個名爲GetMappedFileName的API函數,這個函數能夠實現從
mapping對象的句柄獲得被映射文件的路徑。可是路徑是以設備名的形式給出的,如相似於
「/Device/HarddiskVolume3/1.TXT」的形式。
將設備名轉換爲路徑名須要使用到一個API函數-QueryDosDevice,這個函數能夠將驅動器的根路徑轉換爲設備名,而後進行循環比較,可得文件路徑。
1.關鍵API
(1)GetMappedFileName。
從映射對象獲取被映射文件的文件設備名,函數原型以下:
(2)QueryDosDevice
獲取MS_DOS設備名,函數原型以下:
◇返回值返回DWORD值,若是成功,則返回值爲lpTargetPath指向字符串的長度,若是失敗爲0。
2.實例4-16經過文件句柄獲取文件路徑
GetFileNameFromHandle經過參數輸入的句柄建立mapping對象,而後調用GetMapped
FileName函數,得到對象所映射的文件的設備名,而後使用QueryDosDevice函數循環判斷
驅動器設備名與路徑的關係,在找到正確的驅動器路徑後,構造好文件路徑並輸出。
-
-
-
-
-
-
-
- #include <windows.h>
- #include <stdio.h>
- #include <tchar.h>
- #include <string.h>
- #include <psapi.h>
-
- #pragma comment (lib, "Psapi.lib")
- #define BUFSIZE 512
-
- BOOL GetFileNameFromHandle(HANDLE hFile) ;
-
-
-
-
-
-
-
-
-
- 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;
- }
-
- 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;
- }
-
- if (0 == GetMappedFileName (GetCurrentProcess(),
- pMem,
- pszFilename,
- MAX_PATH))
- {
- printf("GetMappedFileName error: %d",GetLastError());
- return FALSE;
- }
-
- 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));
-
- if (!QueryDosDevice(szDrive, szName, BUFSIZE))
- {
- printf("QueryDosDevice error: %d",GetLastError());
- return FALSE;
- }
- UINT uNameLen = lstrlen(szName);
- if (uNameLen < MAX_PATH)
- {
-
- bFound = strncmp(pszFilename, szName,uNameLen) == 0;
- if (bFound)
- {
-
- TCHAR szTempFile[MAX_PATH];
- wsprintf(szTempFile,
- TEXT("%s%s"),
- szDrive,
- pszFilename+uNameLen);
- lstrcpy(pszFilename, szTempFile);
- }
- }
-
- while (*p++);
- } while (!bFound && *p);
-
- UnmapViewOfFile(pMem);
- CloseHandle(hFileMap);
- printf("File path is %s/n", pszFilename);
- return TRUE;
- }
-
-
-
-
-
-
-
-
-
-
- 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;
- }
-
- 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;
- }