Win32檔案系統編程一丶瞭解什麼是檔案系統
檔案系統是抽象的.是windows在軟體層面提供的一層虛擬資料結構.
檔案系統分為NTFS 跟 FAT32. 具體看看兩者的區別吧.
磁碟分割容量.
單個檔案容量. 意思就是一個檔案可以是多大的. NTFS 是可以4G以上的大檔案. FAT32則不可以.
EFS加密. 這個加密主要針對目前使用者的(例如Admins 管理員賬戶) 具體可以 點擊一個檔案. 檔案->屬性 -> 進階 -> 加密保護檔案內容.
如果在目前使用者則不會有什麼結果. 但是如果換了使用者訪問.則不可以訪問這個加密檔案了.
加密後的檔案.
檔案顏色都會改變.
磁碟配額 意思就是可以限制別的使用者訪問這個硬碟多少G記憶體.
具體設定 xp下 盤符屬性-> 配額
關於上面的講解我們只需要瞭解即可.不深究.具體的的是學習API. API為我們封裝好了.我們並不用關心NTFS 或者FAT32
二丶Windows提供的操作 "檔案" 的 API
標題中檔案為什麼添加了引號. 意思是不光可以操作檔案. 在windows系統中.一切東西都虛擬為了檔案. 例如管道 等等.. 都可以使用這些API.
api具體介紹
1.瞭解卷 檔案 跟目錄的關係. 卷API
卷指的就是我們的的邏輯硬碟. 例如C盤.
目錄則是C盤裡面的檔案夾. 檔案夾裡面可能還是以檔案夾. 也可能是檔案.
卷操作API 很簡單. 常用的就四個.
DWORD GetLogIcalDrives() 擷取卷 傳回值是10進位.我們需要轉化成16進位.然後轉換成二進位查看.每一位為1代表有這個磁碟.否則則沒有
GetLogIcalDriveStrings(buffsize,buf) 擷取一個卷的盤符的字串
GetDriveType(""目錄名稱") 擷取卷的類型
GetVolumeInformation() 擷取卷的類型
如以下代碼例子:
// A.cpp : 定義控制台應用程式的進入點。//#include "stdafx.h"#include <Windows.h>int main(){ //1.擷取磁碟邏輯驅動卷 DWORD dwGetDrives = GetLogicalDrives(); /* 例如我的傳回值是 252 轉化為16進位 FC 轉化為二進位 11111100 代表我們有六個磁碟. CDEFGH 而我的恰好就是 CDEFGH 盤. */ //2.擷取磁碟卷字串. TCHAR wszBuf[1024] = { NULL }; DWORD dwSize = sizeof(TCHAR) * 1024; GetLogicalDriveStringsW(dwSize, wszBuf); /* 邏輯磁碟機返回後會存在wszBuf裡面. 自己做分割即可. 例如 C:\ B:\ */ //3.根據指定盤符擷取它的類型. 可以移除的還是不可以移除的. DWORD dwDriveType = GetDriveTypeW(TEXT("C:\\")); //具體傳回值查詢MSDN 注意從0開始 //4.擷取卷的詳細資料. DWORD dwVolumneSerial = 0; //驅動卷的序號(不是硬碟序號) DWORD dwFileMaxLen = 0; //系統允許的最大檔案名稱的長度 DWORD dwFileSystem = 0; //檔案系統標識. TCHAR dwFileSystemBuffer[255] = { 0 }; //檔案作業系統的名稱 TCHAR szVolName[255] = { 0 }; //返回的卷的別名 GetVolumeInformationW( TEXT("c:\\"), // IN參數 你要查看那個卷的資訊 szVolName, // OUT參數. 查詢到的卷的別名會給你.例如你的別名是C sizeof(TCHAR) * 255, // IN參數. 上面緩衝區的大小. &dwVolumneSerial, // OUT 驅動卷的序號 &dwFileMaxLen, // OUT 寫檔案讀檔案等等檔案名稱最大可以是多大. &dwFileSystem, // OUT 檔案作業系統標識.有多中宏組合,具體可以查詢MSDN. 標識你這個檔案是 dwFileSystemBuffer, //你當前系統是 NTFS 還是FAT32 sizeof(TCHAR) * 255 //上面緩衝區的大小. ); return 0;}2.檔案夾(目錄) 操作的相關API
CreateDirectory();//建立目錄
RemoveDirectory();//刪除目錄
MoveFile(); //修改目錄名稱.
GetCurrentDirectory(); //擷取進程目前的目錄
SetCurrentDirectory(); //設定進程目前的目錄.
具體代碼例子:
main函數調用即可.
void GetDirectoryApi(){ CreateDirectory(TEXT("D:\\123"),NULL);//建立目錄 MoveFile(TEXT("D:\\123"), TEXT("D:\\456")); //修改目錄名稱. RemoveDirectory(TEXT("D:\\456"));//刪除目錄 TCHAR szCurrentDirectoryBuffer[255] = { 0 }; DWORD dwBuffsize = sizeof(TCHAR) * 255; GetCurrentDirectory(dwBuffsize, szCurrentDirectoryBuffer); //擷取目前的目錄 SetCurrentDirectory(szCurrentDirectoryBuffer); //設定目前的目錄.}3.檔案操作相關API
CreateFile( ) 建立檔案
DeleteFile(); 刪除檔案
CloseHandle(); 關閉檔案控制代碼
GetFileSize(); 擷取檔案大小.
ReadFile(); 讀檔案
WriteFile(); 寫檔案
CopyFile(); 拷貝檔案
具體看如下代碼詳解參數意義.
void OptFileApi(){ //1.建立檔案 HANDLE hFile = CreateFile( TEXT("D:\\123.txt"), //你要建立的檔案名稱 GENERIC_READ | GENERIC_WRITE, // 建立的這個檔案唯讀模式建立時唯寫模式建立還是讀寫都可以.如果唯讀則不可以寫. 0, // 檔案分享權限設定模式. 意思就是你這個檔案建立完畢之後.當前讀寫只能有一個人在用,其他人不能操作. 為0就是排他. 或者說你可以設定為其他人可以讀. NULL, // 每個核心對象都有的SD安全屬性 OPEN_EXISTING, //建立檔案的資訊. 你這個檔案是檔案不存在就建立 還是開啟已經存在的. 還是總是建立新的. FILE_ATTRIBUTE_NORMAL, //建立的檔案屬性. 意思就是我建立的這個檔案是隱藏檔案啊 還是別的檔案. 反正就是屬性. NULL ); //2.擷取檔案大小 DWORD dwLowSize = 0; DWORD dwHighSize = 0; dwLowSize = GetFileSize(hFile, &dwHighSize); //如果是32位系統.傳回值儲存了大小.如果是64位系統.則高32位也會儲存. //3.寫檔案 TCHAR szBuffer[1024] =TEXT("HelloFile"); DWORD dwSize = sizeof(TCHAR) * 1024; DWORD OutSize = 0; WriteFile(hFile, //往哪個檔案中寫 szBuffer, //寫入的Buffer資料 dwSize, //寫入的大小 &OutSize, //實際寫入的大小.作業系統返回給你 NULL); //非同步作業不需要 //4.讀檔案 //4.1設定File讀取位置 SetFilePointer(hFile, //讀取那個檔案 1, //低32位的位移.具體位移 就是從檔案開始位置 + 位移位置讀取. 如果是64位那麼第三個參數也要使用. 0, FILE_BEGIN //位移起始位置. 檔案開始 檔案結束. 還是檔案中間 ); ReadFile(hFile, //讀哪個 szBuffer, //讀入的資料放到Buffer dwSize, //Buffer大小 &OutSize, //實際讀入的大小.作業系統返回給你 NULL); //非同步作業不需要 CloseHandle(hFile); //5.拷貝檔案 CopyFile( TEXT("D:\\123.txt"), //源檔案 TEXT("E:\\123.txt"), //目的檔案 TRUE //是否覆蓋目的檔案 ); //.關閉檔案控制代碼 //6.刪除檔案 DeleteFile(TEXT("d:\\123.txt"));} 三丶記憶體對應檔
我們上幾篇部落格講解了CreateFileMaping 建立實體記憶體頁. 那麼我們可以把檔案跟物理頁綁定.
例如:
其實檔案對應到實體記憶體了.那麼我們直接操作記憶體就可以. 想相當於操作檔案.
具體步驟.
1.建立檔案.如果檔案已經存在.則開啟檔案.擷取檔案控制代碼.
2.申請共用記憶體.使用CreateFileMapping. 將檔案控制代碼傳入.
3,將實體記憶體映射到線性地址(虛擬記憶體)中.使用 MapViewOfFile.
4.操作的虛擬位址就是檔案內容了.
具體看如下代碼.
void OptFileApi(){ //1.建立檔案 HANDLE hFile = CreateFile( TEXT("D:\\calc.exe"), //你要建立的檔案名稱 GENERIC_READ | GENERIC_WRITE, // 建立的這個檔案唯讀模式建立時唯寫模式建立還是讀寫都可以.如果唯讀則不可以寫. 0, // 檔案分享權限設定模式. 意思就是你這個檔案建立完畢之後.當前讀寫只能有一個人在用,其他人不能操作. 為0就是排他. 或者說你可以設定為其他人可以讀. NULL, // 每個核心對象都有的SD安全屬性 OPEN_EXISTING, //建立檔案的資訊. 你這個檔案是檔案不存在就建立 還是開啟已經存在的. 還是總是建立新的. FILE_ATTRIBUTE_NORMAL, //建立的檔案屬性. 意思就是我建立的這個檔案是隱藏檔案啊 還是別的檔案. 反正就是屬性. NULL ); //2.建立記憶體物理頁.跟檔案掛靠 HANDLE hFileMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE,0, 0X1000, NULL); //讀寫的方式映射.不需要其它進程使用. //3.映射到虛擬記憶體位置. LPVOID szBuffer = MapViewOfFile(hFileMap, FILE_MAP_ALL_ACCESS, 0, 0, 0); //直接操作記憶體即可. printf("%x",*(PDWORD)szBuffer); //列印前四個位元組. *(PDWORD)szBuffer = 0xFFFF0000; //修改檔案前四個位元組. /* 此API可以 強制更新緩衝. BOOL FlushViewOfFile( LPCVOID lpBaseAddress, // starting address SIZE_T dwNumberOfBytesToFlush // number of bytes in range); */ //4.取消映射 UnmapViewOfFile(szBuffer); CloseHandle(hFileMap); CloseHandle(hFile);}
如果映射到虛擬記憶體中.也就是調用完畢 MapViewOfFile的時候.其緩衝區就是檔案的起始位置. 可以直接指標修改了.
例如我們的Calc計算機.頭四個位元組已經被我們修改成了 0xFFFF了.
很簡單. 多動手做即可.
四丶記憶體對應檔之多進程共用.
如所示:
A進程映射實體記憶體.並且對應檔. B進程使用這塊實體記憶體其實也是操作檔案.
只不過附帶了一個檔案.修改修改實體記憶體的時候變成修改檔案了.具體代碼不在貼了.
主需要申請共用記憶體的時候給定一個名字. 那麼雙進程就可以使用了.