1、文件操作的方法
???使用Visual C++編程,有如下方法進(jìn)行文件操作:
(1)使用標(biāo)準(zhǔn)C運(yùn)行庫(kù)函數(shù),包括fopen、fclose、fseek等。
???(2)使用Win16下的文件和目錄操作函數(shù),如lopen、lclose、lseek等。不過(guò),在Win32下,這些函數(shù)主要是為了和Win16向后兼容。
???(3)使用Win32下的文件和目錄操作函數(shù),如CreateFile,CopyFile,DeleteFile,F(xiàn)indNextFile,等等。
??????Win32下,打開(kāi)和創(chuàng)建文件都由CreateFile完成,成功的話,得到一個(gè)Win32下的句柄,這不同于“C”的fopen返回的句柄。在Win16下,該句柄和C運(yùn)行庫(kù)文件操作函數(shù)相容。但在Win32下,“C”的文件操作函數(shù)不能使用該句柄,如果需要的話,可以使用函數(shù)_open_osfhandle從Win32句柄得到一個(gè)“C”文件函數(shù)可以使用的文件句柄。
關(guān)閉文件使用Win32的CloseHandle。
在Win32下,CreateFile可以操作的對(duì)象除了磁盤(pán)文件外,還包括設(shè)備文件如通訊端口、管道、控制臺(tái)輸入、郵件槽等等。
(4)使用CFile和其派生類(lèi)進(jìn)行文件操作。CFile從CObject派生,其派生類(lèi)包括操作文本文件的CStdioFile,操作內(nèi)存文件的CmemFile,等等。CFile是建立在Win32的文件操作體系的基礎(chǔ)上,它封裝了部分Win32文件操作函數(shù)。最好是使用CFile類(lèi)(或派生類(lèi))的對(duì)象來(lái)操作文件,必要的話,可以從這些類(lèi)派生自己的文件操作類(lèi)。統(tǒng)一使用CFile的界面可以得到好的移植性。
2、文件操作的方法
MFC用一些類(lèi)來(lái)封裝文件訪問(wèn)的Win32 API。以CFile為基礎(chǔ),從CFile派生出幾個(gè)類(lèi),如CStdioFile,CMemFile,MFC內(nèi)部使用的CMiororFile,等等。
2.1、CFile的結(jié)構(gòu)
?????2.1.1、CFile定義的枚舉類(lèi)型
???????????????CFile類(lèi)定義了一些和文件操作相關(guān)的枚舉類(lèi)型,主要有四種:OpenFlags,Attribute,SeekPosition,hFileNull。下面,分別解釋這些枚舉類(lèi)型。
- OpenFlags
OpenFlags定義了13種文件訪問(wèn)和共享模式:
enum OpenFlags {
//第一(從右,下同)至第二位,打開(kāi)文件時(shí)訪問(wèn)模式,讀/寫(xiě)/讀寫(xiě)
modeRead = 0x0000,
modeWrite = 0x0001,
modeReadWrite = 0x0002,
shareCompat = 0x0000, //32位MFC中沒(méi)用
//第五到第七位,打開(kāi)文件時(shí)的共享模式
shareExclusive = 0x0010,//獨(dú)占方式,禁止其他進(jìn)程讀寫(xiě)
shareDenyWrite = 0x0020,//禁止其他進(jìn)程寫(xiě)
shareDenyRead = 0x0030,//禁止其他進(jìn)程讀
shareDenyNone = 0x0040,//允許其他進(jìn)程寫(xiě)
//第八位,打開(kāi)文件時(shí)的文件繼承方式
modeNoInherit = 0x0080,//不允許子進(jìn)程繼承
//第十三、十四位,是否創(chuàng)建新文件和創(chuàng)建方式
modeCreate = 0x1000,//創(chuàng)建新文件,文件長(zhǎng)度0
modeNoTruncate = 0x2000,//創(chuàng)建新文件時(shí)如文件已存在則打開(kāi)
//第十五、十六位,文件以二進(jìn)制或者文本方式打開(kāi),在派生類(lèi)CStdioFile中用
typeText = 0x4000,
typeBinary = (int)0x8000
};
- Attribute
Attribute定義了文件屬性:正常、只讀、隱含、系統(tǒng)文件,文件或者目錄等。
enum Attribute {
normal = 0x00,
readOnly = 0x01,
hidden = 0x02,
system = 0x04,
volume = 0x08,
directory = 0x10,
archive = 0x20
}
- SeekPosition
SeekPosition定義了三種文件位置:頭、尾、當(dāng)前:
enum SeekPosition{
begin = 0x0,
current = 0x1,
end = 0x2
};
- hFileNull
hFileNull定義了空文件句柄
enum { hFileNull = -1 };
2.1.2、CFile的其他一些成員變量
CFile除了定義枚舉類(lèi)型,還定義了一些成員變量。例如:
UINT m_hFile
該成員變量是public訪問(wèn)屬性,保存::CreateFile返回的操作系統(tǒng)的文件句柄。MFC重載了運(yùn)算符號(hào)HFILE來(lái)返回m_hFile,這樣在使用HFILE類(lèi)型變量的地方可以使用CFile對(duì)象。
BOOL m_bCloseOnDelete;
CString m_strFileName;
這兩個(gè)成員變量是protected訪問(wèn)屬性。m_bCloseOnDelete用來(lái)指示是否在關(guān)閉文件時(shí)刪除CFile對(duì)象;m_strFileName用來(lái)保存文件名。
2.1.3、CFile的成員函數(shù)
CFile的成員函數(shù)實(shí)現(xiàn)了對(duì)Win32文件操作函數(shù)的封裝,完成以下動(dòng)作:打開(kāi)、創(chuàng)建、關(guān)閉文件,文件指針定位,文件的鎖定與解鎖,文件狀態(tài)的讀取和修改,等等。其中,用到了m_hFile文件句柄的一般是虛擬函數(shù),和此無(wú)關(guān)的一般是靜態(tài)成員函數(shù)。一般地,成員函數(shù)被映射到對(duì)應(yīng)的Win32函數(shù),如表11-1所示。
表11-1 CFile函數(shù)對(duì)Win32文件函數(shù)的封裝
虛擬
|
靜態(tài)
|
成員函數(shù)
|
對(duì)應(yīng)的Win32函數(shù)
|
文件的創(chuàng)建、打開(kāi)、關(guān)閉
|
√
|
|
Abort
|
CloseHandle
|
√
|
|
Duplicate
|
DuplicateHandle
|
√
|
|
Open
|
CreateFile
|
√
|
|
Close
|
CloseHandle
|
文件的讀寫(xiě)
|
√
|
|
Read
|
ReadFile
|
|
|
ReadHuge(向后兼容)
|
調(diào)用Read成員函數(shù)
|
√
|
|
Write
|
WriteFile
|
|
|
WriteHuage(向后兼容)
|
調(diào)用Write成員函數(shù)
|
√
|
|
Flush
|
FlushFileBuffers
|
文件定位
|
√
|
|
Seek
|
SetFilePointer
|
|
|
SeekToBegin
|
調(diào)用Seek成員函數(shù)
|
|
|
SeekToEnd
|
調(diào)用Seek成員函數(shù)
|
√
|
|
GetLength
|
調(diào)用Seek成員函數(shù)
|
√
|
|
SetLength
|
SetEndOfFile
|
文件的鎖定/解鎖
|
√
|
|
LockRange
|
LockFile
|
√
|
|
UnlockRange
|
UnlockFile
|
文件狀態(tài)操作函數(shù)
|
√
|
|
GetPosition
|
SetFilePointer
|
|
|
GetStatus(CFileStatus&)
|
GetFileTime,GetFileSize等
|
|
√
|
GetStatus(LPSTR lpszFileName CFileStatus&)
|
FindFirstFile
|
√
|
|
GetFileName
|
不是簡(jiǎn)單地映射到某個(gè)函數(shù)
|
√
|
|
GetFileTitle
|
|
√
|
|
GetFilePath
|
|
√
|
|
SetFilePath
|
|
|
√
|
SetStatus
|
|
改名和刪除
|
|
√
|
Rename
|
MoveFile
|
|
√
|
Remove
|
DeleteFile
|
2.1.4、CFile的部分實(shí)現(xiàn)
這里主要討論CFile對(duì)象的構(gòu)造函數(shù)和文件的打開(kāi)/創(chuàng)建的過(guò)程。
- 構(gòu)造函數(shù)
CFile有如下幾個(gè)構(gòu)造函數(shù):
缺省構(gòu)造函數(shù),僅僅構(gòu)造一個(gè)CFile對(duì)象,還必須使用Open成員函數(shù)來(lái)打開(kāi)文件。
已經(jīng)打開(kāi)了一個(gè)文件hFile,在此基礎(chǔ)上構(gòu)造一個(gè)CFile對(duì)象來(lái)給它打包。HFile將被賦值給CFile的成員變量m_hFile。
- CFile(LPCTSTR lpszFileName, UINT nOpenFlags)
指定一個(gè)文件名和文件打開(kāi)方式,構(gòu)造CFile對(duì)象,調(diào)用Open打開(kāi)/創(chuàng)建文件,把文件句柄保存到m_hFile。
- 打開(kāi)/創(chuàng)建文件
Open的原型如下:
BOOL CFile::Open(LPCTSTR lpszFileName, UINT nOpenFlags,
CFileException* pException)
Open調(diào)用Win32函數(shù)::CreateFile打開(kāi)文件,并把文件句柄保存到成員變量m_hFile中。
CreateFile函數(shù)的原型如下:
HANDLE CreateFile(
LPCTSTR lpFileName,// pointer to name of the file
DWORD dwDesiredAccess,// access (read-write) mode
DWORD dwShareMode,// share mode
LPSECURITY_ATTRIBUTES lpSecurityAttributes, //pointer to security descriptor
DWORD dwCreationDistribution,// how to create
DWORD dwFlagsAndAttributes,// file attributes
HANDLE hTemplateFile// handle to file with attributes to copy
);
顯然,Open必須把自己的兩個(gè)參數(shù)lpszFileName和nOpenFlags映射到CreateFile的七個(gè)參數(shù)上。
從OpenFlags的定義可以看出,(nOpenFlags & 3)表示了讀寫(xiě)標(biāo)識(shí),映射成變量dwAccess,可以取值為Win32的GENERIC_READ、GENERIC_WRITE、GENERIC_READ|GENERIC_WRITE。
(nOpenFlags & 0x70)表示了共享模式,映射成變量dwShareMode,可以取值為Win32的FILE_SHARE_READ、FILE_SHARE_WRITE、FILE_SHARE_WRITE|FILE_SHARE_READ。
Open定義了一個(gè)局部的SECURITY_ATTRIBUTES變量sa,(nOpenFlags & 0x80)被賦值給sa.bInheritHandle。
(nOpenFlags & modeCreate)表示了創(chuàng)建方式,映射成變量dwCreateFlag,可以取值為Win32的OPEN_ALWAYS、CREATE_ALWAYS、OPEN_EXISTING。
在生成了上述參數(shù)之后,先調(diào)用::CreateFile:
HANDLE hFile =::CreateFile(lpszFileName,
dwAccess, dwShareMode, &sa,
dwCreateFlag, FILE_ATTRIBUTE_NORMAL, NULL);
然后,hFile被賦值給成員變量m_hFile,m_bCloseOnDelete被設(shè)置為T(mén)RUE。
由上可以看出,CFile打開(kāi)(創(chuàng)建)一個(gè)文件時(shí)大大簡(jiǎn)化了:: CreateFile函數(shù)的復(fù)雜性,即只需要指定一個(gè)文件名、一個(gè)打開(kāi)文件的參數(shù)即可。若該參數(shù)指定為0,則表示以只讀方式打開(kāi)一個(gè)存在的文件,獨(dú)占使用,不允許子進(jìn)程繼承。
在CFile對(duì)象使用時(shí),如果它是在堆中分配的,則應(yīng)該銷(xiāo)毀它;如果在棧中分配的,則CFile對(duì)象將被自動(dòng)銷(xiāo)毀。銷(xiāo)毀時(shí)析構(gòu)函數(shù)被調(diào)用,析構(gòu)函數(shù)是虛擬函數(shù)。若m_bCloseOnDelete為真且m_hFile非空,則析構(gòu)函數(shù)調(diào)用Close關(guān)閉文件。
至于其他CFile成員函數(shù)的實(shí)現(xiàn),這里不作分析了。
2.1.5、CFile的派生類(lèi)
這里主要簡(jiǎn)要地介紹CStdioFile和CmemFile及CFileFind。
- CStdioFile
CStdioFile對(duì)文本文件進(jìn)行操作。
CStdioFile定義了新的成員變量m_pStream,類(lèi)型是FILE*。在打開(kāi)或者創(chuàng)建文件時(shí),使用_open_osfhandle從m_hFile(Win32文件句柄)得到一個(gè)“C”的FILE類(lèi)型的文件指針,然后,在文件操作中,使用“C”的文件操作函數(shù)。例如,讀文件使用_fread,而不是::ReadFile,寫(xiě)文件使用了_fwrite,而不是::WriteFile,等等。m_hFile是CFile的成員變量。
另外,CStdioFile不支持CFile的Dumplicate、LockRange、UnlockRange操作,但是實(shí)現(xiàn)了兩個(gè)新的操作ReadString和WriteString。
- CMemFile
CMemFile把一塊內(nèi)存當(dāng)作一個(gè)文件來(lái)操作,所以,它沒(méi)有打開(kāi)文件的操作,而是設(shè)計(jì)了Attach和Detach用來(lái)分配或者釋放一塊內(nèi)存。相應(yīng)地,它提供了Alloc、Free虛擬函數(shù)來(lái)操作內(nèi)存文件,它覆蓋了Read、Write來(lái)讀寫(xiě)內(nèi)存文件。
- CFileFind
為了方便文件查找,MFC把有關(guān)功能歸結(jié)成為一個(gè)類(lèi)CFileFind。CFileFind派生于CObject類(lèi)。首先,它使用FindFile和FineNextFile包裝了Win32函數(shù)::FindFirstFile和::FindNextFile;其次,它提供了許多函數(shù)用來(lái)獲取文件的狀態(tài)或者屬性。
使用CFileStatus結(jié)構(gòu)來(lái)描述文件的屬性,其定義如下:
struct CFileStatus
{
CTime m_ctime; // 文件創(chuàng)建時(shí)間
CTime m_mtime; // 文件最近一次修改時(shí)間
CTime m_atime; // 文件最近一次訪問(wèn)時(shí)間
LONG m_size; // 文件大小
BYTE m_attribute; // 文件屬性
BYTE _m_padding; // 沒(méi)有實(shí)際含義,用來(lái)增加一個(gè)字節(jié)
TCHAR m_szFullName[_MAX_PATH]; //絕對(duì)路徑
#ifdef _DEBUG
//實(shí)現(xiàn)Dump虛擬函數(shù),輸出文件屬性
void Dump(CDumpContext& dc) const;
#endif
};
例如:
CFileStatus status;
pFile->GetStatus(status);
#ifdef _DEBUG
status.dump(afxDump);
#endif