一、基本概念
1、磁盤分區(Partitions)
磁盤是裝到計算機上的儲存設備,比如常見的硬碟。磁盤分區是為了便于管理和使用實體硬碟,而在一個實體硬碟上劃分可以各自獨立工作的一些邏輯磁盤。比如一塊80GB的硬碟可以劃分為4個20GB的分區來使用,對作業系統來說這4個20GB的分區是4塊獨立的邏輯磁盤。
2、卷(Volumes)
卷,也稱為邏輯驅動器,是NTFS、FAT32等檔案系統組織結構的最高層。卷是儲存設備(如硬碟)上由檔案系統管理的一塊區域,是在邏輯上互相隔離的存儲單元。一個磁盤分區至少含有一個卷,卷也可以存在于多個磁盤分區上,僅存在于一個磁盤分區上的卷稱為“簡單磁碟區”,僅存在于多個磁盤分區上的卷稱為“多分區卷”或“跨距磁碟區”。在最常見的情況下,一個分區隻包含一個卷,一個卷也隻存在于一個分區上,是以兩者容易混淆。卷存在卷标,程式可以通過卷标通路卷。
在Windows系統中,檔案路徑的長度被限制260個字元,這260個字元包括卷标、路徑、主檔案名和擴充名以及分隔符,是以,檔案名的長度為260減去檔案所在目标的路徑長度。在Windows NT系統中,字元使用的是Unicode寬字元。英文和中文都占用兩個位元組。
特殊字元則不能在檔案名的任何位置出現。特殊字元一共有9個,分别為:“/”、“∣”“\”、“*”、“?”、"<"、“>”、“””、“:”。特殊字元在系統或者指令行下代表一些特殊意義。
二、檔案系統API

三、注意點
1、檔案名,可以是絕對路徑或相對路徑。
2、重命名也是用移動檔案MoveFile。
3、可以看到:
◇在程序中使用相對路徑,則相對路徑的起始點是程式的目前路徑而不是可執行檔案所在的路徑。
◇程序的目前路徑在預設情況下是應用程式可執行檔案所在的路徑。
◇子產品路徑與程式的目前路徑是兩個概念,程序的主程式和程序中所加載的所有DLL都是程序的子產品。
四、示例程式
1、示例周遊指定目錄
示例周遊指定目錄
/* ************************************
*《精通Windows API》
* 示例代碼
* sub_dir.c
* 4.3.5 周遊目錄下的檔案和子目錄
**************************************/
/* 頭檔案 */
#include <windows.h>
#include <stdio.h>
* DWORD EnumerateFileInDrectory(LPSTR szPath)
* 功能 周遊目錄下的檔案和子目錄,将顯示檔案的
* 檔案和檔案夾隐藏、加密的屬性
* 參數 LPTSTR szPath,為需周遊的路徑
* 傳回值 0代表執行完成,1代碼發生錯誤
DWORD EnumerateFileInDrectory(LPSTR szPath)
{
WIN32_FIND_DATA FindFileData;
HANDLE hListFile;
CHAR szFilePath[MAX_PATH];
//構造代表子目錄和檔案夾路徑的字元串,使用通配符“*”
lstrcpy(szFilePath, szPath);
//注釋的代碼可以用于查找所有以“.txt結尾”的檔案。
//lstrcat(szFilePath, "\\*.txt");
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[])
* 功能 調用ListFileInDrectory
* 周遊目錄下的檔案和子目錄
* 參數 argv[1]為需周遊的路徑,如果為空則擷取
* 目前路徑
int main(int argc, PCHAR argv[])
if(argc == 2)
EnumerateFileInDrectory(argv[1]);
CHAR szCurrentPath[MAX_PATH];
GetCurrentDirectory(MAX_PATH,szCurrentPath);
EnumerateFileInDrectory(szCurrentPath);
2、示例周遊目錄樹
示例周遊目錄樹
* tree.c
* 4.3.6 遞歸周遊目錄樹
* 2007年10月
/* 預處理申明 */
#pragma comment (lib, "User32.lib")
/* 函數申明 */
DWORD ListAllFileInDrectory(LPSTR szPath);
/* 全局變量 */
//記錄所有的檔案和目錄數
DWORD dwTotalFileNum = 0;
* DWORD ListAllFileInDrectory(LPSTR szPath)
* 功能 周遊目錄及所有子目錄,列印路徑
*
* 參數 LPTSTR szPath,為需周遊的目錄
DWORD ListAllFileInDrectory(LPSTR szPath)
CHAR szFullPath[MAX_PATH];
// 過濾“.”和“..”,不需要周遊
//構造成全路徑
wsprintf(szFullPath,"%s\\%s",
szPath,FindFileData.cFileName);
dwTotalFileNum++;
//列印
printf("\n%d\t%s\t",dwTotalFileNum,szFullPath);
//如果是目錄,則遞歸調用,列舉下級目錄
printf("<DIR>");
ListAllFileInDrectory(szFullPath);
* 功能 調用ListAllFileInDrectory
ListAllFileInDrectory(argv[1]);
ListAllFileInDrectory(szCurrentPath);
3、示例擷取目前時間
示例擷取目前時間
* attr.c
* 4.3.7 擷取、設定檔案屬性和時間
DWORD ShowFileTime(PFILETIME lptime);
DWORD ShowFileSize(DWORD dwFileSizeHigh,DWORD dwFileSizeLow);
DWORD ShowFileAttrInfo(DWORD dwAttribute);
DWORD SetFileHiddenAndReadonly(LPSTR szFileName);
* DWORD ShowFileAttributes(LPSTR szPath)
* 功能 擷取并顯示檔案屬性,
* 調用ShowFileTime、ShowFileSize和
* ShowFileAttrInfo函數
* 參數 LPTSTR szPath,擷取并顯示此檔案的屬性
DWORD ShowFileAttributes(LPSTR szPath)
//檔案屬性結構
WIN32_FILE_ATTRIBUTE_DATA wfad;
printf("檔案:%s\n",szPath);
//擷取檔案屬性
if(!GetFileAttributesEx(szPath,
GetFileExInfoStandard,
&wfad))
printf("擷取檔案屬性錯誤:%d\n",GetLastError());
//顯示相關時間
printf("建立時間:\t");
ShowFileTime(&(wfad.ftCreationTime));
printf("最後通路時間:\t");
ShowFileTime(&(wfad.ftLastAccessTime));
printf("最後修改時間:\t");
ShowFileTime(&(wfad.ftLastWriteTime));
//顯示檔案大小
ShowFileSize(wfad.nFileSizeHigh,wfad.nFileSizeLow);
//顯示檔案屬性
ShowFileAttrInfo(wfad.dwFileAttributes);
* DWORD ShowFileAttrInfo(DWORD dwAttribute)
* 功能 列印将檔案屬性
* 參數 DWORD dwAttribute,檔案屬性
* 傳回值 0
DWORD ShowFileAttrInfo(DWORD dwAttribute)
//依次判斷屬性,并顯示。
printf("檔案屬性:\t");
if(dwAttribute&FILE_ATTRIBUTE_ARCHIVE)
printf("<ARCHIVE> ");
if(dwAttribute&FILE_ATTRIBUTE_COMPRESSED)
printf("<壓縮> ");
if(dwAttribute&FILE_ATTRIBUTE_DIRECTORY)
printf("<目錄> ");
if(dwAttribute&FILE_ATTRIBUTE_ENCRYPTED)
if(dwAttribute&FILE_ATTRIBUTE_HIDDEN)
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("<臨時檔案> ");
* DWORD ShowFileSize(DWORD dwFileSizeHigh, DWORD dwFileSizeLow)
* 功能 列印檔案大小資訊
* 參數 DWORD dwFileSizeHigh,檔案大小高32位
* DWORD dwFileSizeLow,檔案大小低32位
DWORD ShowFileSize(DWORD dwFileSizeHigh, DWORD dwFileSizeLow)
ULONGLONG liFileSize;
liFileSize = dwFileSizeHigh;
//高們移動32位
liFileSize <<= sizeof(DWORD)*8;
liFileSize += dwFileSizeLow;
printf("檔案大小:\t%I64u 位元組\n",liFileSize);
*DWORD ShowFileTime(PFILETIME lptime)
* 功能 輪換檔案時間,将列印
* 參數 PFILETIME lptime,指向檔案時間的指針
DWORD ShowFileTime(PFILETIME lptime)
//檔案時間結構
FILETIME ftLocal;
//系統時間結構
SYSTEMTIME st;
//調整為系統所在時區的時間
FileTimeToLocalFileTime(
lptime,
&ftLocal
);
//将檔案時間轉換為SYSTEMTIME格式,便于顯示。
FileTimeToSystemTime(
&ftLocal,
&st
//顯示時間資訊字元串
printf("%4d年%.2d月%#02d日,%.2d:%.2d:%.2d\n",
st.wYear,st.wMonth,st.wDay,st.wHour,st.wMinute,st.wSecond);
* DWORD SetFileHiddenAndReadonly(LPSTR szFileName)
* 功能 将指定的檔案設定為隐藏和隻讀
* 參數 LPSTR szFileName,檔案路徑
DWORD SetFileHiddenAndReadonly(LPSTR szFileName)
//擷取原來的檔案屬性
DWORD dwFileAttributes = GetFileAttributes(szFileName);
//将隻讀和隐藏屬性附加到原來的檔案屬性上
dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
//設定檔案屬性,并判斷是否成功。
if(SetFileAttributes(szFileName, dwFileAttributes))
printf("檔案%s的隐藏和屬性設定成功\n",szFileName);
printf("屬性設定; %d\n",GetLastError());
* 功能 設定和擷取檔案屬性等
* 參數 顯示第一個參數指定檔案的屬性、時間、大小
* 将第二個參數的屬性設定為隐藏、隻讀。
if(argc != 3)
printf("請輸入參數\n");
printf("顯示第一個參數指定檔案的屬性、時間、大小;\n");
printf("将第二個參數的屬性設定為隐藏、隻讀。");
ShowFileAttributes(argv[1]);
SetFileHiddenAndReadonly(argv[2]);
五、記憶體映射檔案
◇使用Mapping File提高檔案讀寫的效率。
◇通過Mapping File在程序間共享記憶體。
◇通過檔案句柄獲得檔案路徑。
檔案映射( mapping)是一種在将檔案内容映射到程序的虛拟位址空間的技術。視圖(View)是一段虛拟位址空間,程序可以通過View來存取檔案的内容,視圖是一段記憶體,可以使用指針來操作視圖。使用的檔案映射之後,讀寫檔案就如同對讀寫記憶體一樣簡單。在使用檔案映射時需要建立映射對象,映射對象分為命名的和未命名的。映射對象還存取權限。
使用檔案映射至少有3個好處,一是因為檔案是存儲于硬碟上的,而檔案視圖是一段記憶體,使用檔案映射操作時更友善;二是效率更高;三是可以在不同的程序間共享資料。
檔案映射依賴于系統虛拟記憶體管理的分頁機制。
1、如何使用檔案映射
代碼
* file_map.c
* 4.4.1 使用Mapping File提高檔案讀寫的效率
/* 預處理申明 */
#define BUFFSIZE 1024 // 記憶體大小
#define FILE_MAP_START 0x28804 // 檔案映射的起始的位置
LPTSTR lpcTheFile = TEXT("test.dat"); // 檔案名
* int main(void)
* 功能 示範使用檔案mapping
* 參數 無
* 傳回值 0代表執行完成,1代表發生錯誤
int main(void)
HANDLE hMapFile; // 檔案記憶體映射區域的句柄
HANDLE hFile; // 檔案的句柄
DWORD dBytesWritten; // 寫入的位元組數
DWORD dwFileSize; // 檔案大小
DWORD dwFileMapSize; // 檔案映射的大小
DWORD dwMapViewSize; // 視圖(View)的大小
DWORD dwFileMapStart; // 檔案映射視圖的起始位置
DWORD dwSysGran; // 系統記憶體配置設定的粒度
SYSTEM_INFO SysInfo; // 系統資訊
LPVOID lpMapAddress; // 内在映射區域的起始位置
PCHAR pData; // 資料
INT i; // 循環變量
INT iData;
INT iViewDelta;
BYTE cMapBuffer[32]; // 存儲從mapping中計出的資料
// 建立一個檔案
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);
// 依次寫入整數,一共寫入65535個整數
// 在32位平台下,大小為65535*32
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;
//計算mapping的起始位置
dwFileMapStart = (FILE_MAP_START / dwSysGran) * dwSysGran;
// 計算mapping view的大小
dwMapViewSize = (FILE_MAP_START % dwSysGran) + BUFFSIZE;
// 計算mapping的大小
dwFileMapSize = FILE_MAP_START + BUFFSIZE;
// 計算需要讀取的資料的偏移
iViewDelta = FILE_MAP_START - dwFileMapStart;
// 建立File mapping
hMapFile = CreateFileMapping( hFile, // 需要映射的檔案的句柄
NULL, // 安全選項:預設
PAGE_READWRITE, // 可讀,可寫
0, // mapping對象的大小,高位
dwFileMapSize, // mapping對象的大小,低位
NULL); // mapping對象的名字
if (hMapFile == NULL)
printf("CreateFileMapping error: %d\n", GetLastError() );
// 映射view
lpMapAddress = MapViewOfFile(hMapFile, // mapping對象的句柄
FILE_MAP_ALL_ACCESS, // 可讀,可寫
0, // 映射的檔案偏移,高32位
dwFileMapStart, // 映射的檔案偏移,低32位
dwMapViewSize); // 映射到View的資料大小
if (lpMapAddress == NULL)
printf("MapViewOfFile error: %d\n", GetLastError());
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);
// 從mapping中複制資料,32個位元組,并列印
CopyMemory(cMapBuffer,lpMapAddress,32);
printf("lpMapAddress起始的32位元組是:");
for(i=0; i<32; i++)
printf("0x%.2x ",cMapBuffer[i]);
// 将mapping的前32個位元組用0xff填充
FillMemory(lpMapAddress,32,(BYTE)0xff);
// 将映射的資料寫回到硬碟上
FlushViewOfFile(lpMapAddress,dwMapViewSize);
printf("\n已經将lpMapAddress開始的32位元組使用0xff填充。\n");
// 關閉mapping對象
if(!CloseHandle(hMapFile))
printf("\nclosing the mapping object error %d!",
GetLastError());
//關閉檔案
if(!CloseHandle(hFile))
printf("\nError %ld occurred closing the file!",
2、如何使用檔案映射進行記憶體共享
1)通過Mapping File在程序間傳遞和共享資料
程序間通信、共享資料有很多種方法,檔案映射是常用的一種方法。因為mapping對象系統中是全局的,一個程序建立的Mapping對象可以從另外一個程序中打開,映射視圖就程序間共享的記憶體了。一般在共享的記憶體資料量比較大時,選擇使用檔案映射進行共享。
示例代碼
* pro_s1.c
* 4.4.2 通過Mapping File在程序間共享記憶體
#include <conio.h>
#define BUF_SIZE 256
LPTSTR szName = TEXT("SharedFileMappingObject");
LPTSTR szMsg = TEXT("程序的消息");
* 功能 示範檔案mapping共享記憶體,寫入資料到共享記憶體
* 傳回值 0代表執行完成,代表發生錯誤
void main(int argc, PCHAR argv[])
//檔案映射句柄
HANDLE hMapFile;
//共享資料緩沖區指針
LPTSTR pBuf;
//建立命名的檔案映射,不代表任務硬碟上的檔案
hMapFile = CreateFileMapping(
INVALID_HANDLE_VALUE,
PAGE_READWRITE,
BUF_SIZE,
szName);
if (hMapFile == NULL || hMapFile == INVALID_HANDLE_VALUE)
printf("CreateFileMapping error: %d\n", GetLastError());
return;
//建立View
pBuf = (LPTSTR) MapViewOfFile(hMapFile,
FILE_MAP_ALL_ACCESS,
BUF_SIZE);
if (pBuf == NULL)
printf("MapViewOfFile error %d\n", GetLastError());
//将共享資料複制到檔案映射中,如果運作時輸入了參數則使用參數
if(argc==1)
CopyMemory((PVOID)pBuf, szMsg, strlen(szMsg));
DWORD dwCopyLen = (lstrlen(argv[1])<BUF_SIZE) ? lstrlen(argv[1]): BUF_SIZE;
CopyMemory((PVOID)pBuf, argv[1], dwCopyLen);
printf("運作程式,完成運作後,按任意鍵退出。");
_getch();
//取消映射,退出
UnmapViewOfFile(pBuf);
CloseHandle(hMapFile);
* pro_s2.c
/* 預處理申明*/
TCHAR szName[]=TEXT("SharedFileMappingObject");
* 功能 示範檔案mapping共享記憶體,從共享資料中讀資訊
void main()
//打開檔案mapping
hMapFile = OpenFileMapping(
FALSE,
printf("OpenFileMapping error: %d.\n", GetLastError());
//映射
pBuf = MapViewOfFile(hMapFile,
printf("MapViewOfFile error %d\n", GetLastError());
//消息得到的共享資料
MessageBox(NULL, pBuf, TEXT("Process2"), MB_OK);
//取消mapping,關閉句柄,傳回
2)通過檔案句柄擷取檔案路徑
* handle_path.cpp
* 4.4.3 通過檔案句柄擷取檔案路徑
/* 頭檔案*/
#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)
* 功能 從檔案句柄擷取檔案路徑
* 參數 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;
// 建立mapping對象
hFileMap = CreateFileMapping(hFile,
PAGE_READONLY,
1,
if (!hFileMap)
printf("CreateFileMapping error: %d",GetLastError());
pMem = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 1);
if (!pMem)
printf("MapViewOfFile error: %d",GetLastError());
// 從mapping對象獲得檔案名
if (0 == GetMappedFileName (GetCurrentProcess(),
pMem,
pszFilename,
MAX_PATH))
printf("GetMappedFileName error: %d",GetLastError());
// 将裝置名轉換為路徑
TCHAR szTemp[BUFSIZE] = {0};
if (0 == GetLogicalDriveStrings(BUFSIZE-1, szTemp))
printf("GetLogicalDriveStrings error: %d",GetLastError());
TCHAR szName[MAX_PATH];
TCHAR szDrive[3] = {0};
BOOL bFound = FALSE;
PTCHAR p = szTemp;
CopyMemory(szDrive,p,2*sizeof(TCHAR));
// 通過路徑查找裝置名
if (!QueryDosDevice(szDrive, szName, BUFSIZE))
printf("QueryDosDevice error: %d",GetLastError());
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);
// 循環到下一個NULL
while (*p++);
} while (!bFound && *p);
UnmapViewOfFile(pMem);
CloseHandle(hFileMap);
printf("File path is %s\n", pszFilename);
return TRUE;
* int main()
* 功能 查找第一個目錄中第一個txt檔案
* 打開檔案,并根據檔案句柄獲得檔案路徑。
* 參數 未使用
* 傳回值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");
//CloseHandle(hFind);
printf("find %s at current dir\n",wfd.cFileName);
hFile = CreateFile(wfd.cFileName,
OPEN_EXISTING,
if(hFile == INVALID_HANDLE_VALUE)
printf("create file error, %d",GetLastError());
GetFileNameFromHandle(hFile) ;
CloseHandle(hFile);