使用CFile類對檔案進行讀寫
CFile類提供了對檔案進行開啟,關閉,讀,寫,刪除,重新命名以及獲取檔案資訊等檔案操作的基本功能,足以處理任意型別的檔案操作
一個讀寫檔案的例子:
檔案I/O
雖然使用CArchive類內建的序列化功能是儲存和載入永續性資料的便捷方式,但有時在程式中需要對檔案處理過程擁有更多的控制權,對於這種檔案輸入輸出(I/O)服務的需求,Windows提供了一系列相關的API函式,並由MFC將其封裝為CFile類,提供了對檔案進行開啟,關閉,讀,寫,刪除,重新命名以及獲取檔案資訊等檔案操作的基本功能,足以處理任意型別的檔案操作。CFile類是MFC檔案類的基類,支援無緩衝的二進位制輸入輸出,也可以通過與CArchive類的配合使用而支援對MFC物件的帶緩衝的序列化。
CFile類包含有一個公有型資料成員m_hFile,該資料成員包含了同CFile類物件相關聯的檔案控制代碼。如果沒有指定控制代碼,則該值為CFile::hFileNull。由於該資料成員所包含的意義取決於派生的類,因此一般並不建議使用m_hFile。
通過CFile類來開啟檔案可以採取兩種方式:一種方式是先構造一個CFile類物件然後再呼叫成員函式Open()開啟檔案,另一種方式則直接使用CFile類的建構函式去開啟一個檔案。下面的語句分別演示了用這兩種方法開啟磁碟檔案“C:/TestFile.txt”的過程:
// 先構造一個例項,然後再開啟檔案
CFile file;
file.Open(“C://TestFile.txt”, CFile::modeReadWrite);
……
// 直接通過建構函式開啟檔案
CFile file(“C://TestFile.txt”, CFile::modeReadWrite);
其中引數CFile::modeReadWrite是開啟檔案的模式標誌,CFile類中與之類似的標誌還有十幾個,現集中列表如下:
檔案模式標誌 說明
CFile::modeCreate 建立方式開啟檔案,如檔案已存在則將其長度設定為0
CFile::modeNoInherit 不允許繼承
CFile::modeNoTruncate 建立檔案時如檔案已存在不對其進行截斷
CFile::modeRead 只讀方式開啟檔案
CFile::modeReadWrite 讀寫方式開啟檔案
CFile::modeWrite 寫入方式開啟檔案
CFile::shareCompat 在使用過程中允許其他程序同時開啟檔案
CFile::shareDenyNone 在使用過程中允許其他程序對檔案進行讀寫
CFile::shareDenyRead 在使用過程中不允許其他程序對檔案進行讀取
CFile::shareDenyWrite 在使用過程中不允許其他程序對檔案進行寫入
CFile::shareExclusive 取消對其他程序的所有訪問
CFile::typeBinary 設定檔案為二進位制模式
CFile::typeText 設定檔案為文字模式
這些標誌可以通過“或”運算子而同時使用多個,並以此來滿足多種需求。例如,需要以讀寫方式開啟檔案,如果檔案不存在就建立一個新的,如果檔案已經存在則不將其檔案長度截斷為0。為滿足此條件,可用CFile::modeCreate、CFile::modeReadWrite和CFile::modeNoTruncate等幾種檔案模式標誌來開啟檔案:
CFile file ("C://TestFile.txt", CFile::modeCreate | CFile::modeReadWrite | CFile::modeNoTruncate);
在開啟的檔案不再使用時需要將其關閉,即可以用成員函式Close()關閉也可以通過CFile類的解構函式來完成。當採取後一種方式時,如果檔案還沒有被關閉,解構函式將負責隱式呼叫Close()函式去關閉檔案,這也表明建立在堆上的CFile類物件在超出範圍後將自動被關閉。由於呼叫了物件的解構函式,因此在檔案被關閉的同時CFile物件也被銷燬,而採取Close()方式關閉檔案後,CFile物件仍然存在。所以,在顯式呼叫Close()函式關閉一個檔案後可以繼續用同一個CFile物件去開啟其他的檔案。
檔案讀寫是最常用的檔案操作方式,主要由CFile類成員函式Read()、Write()來實現。其函式原型分別為:
UINT Read( void* lpBuf, UINT nCount );
void Write( const void* lpBuf, UINT nCount );
引數lpBuf為指向存放資料的快取的指標,nCount為要讀入或寫入的位元組數,Read()返回的為實際讀取的位元組數,該數值小於或等於nCount,如果小於nCount則說明已經讀到檔案末尾,可以結束檔案讀取,如繼續讀取,將返回0。因此通常可以將實際讀取位元組數是否小於指定讀取的位元組數或是否為0作為判斷檔案讀取是否到達結尾的依據。下面這段程式碼演示了對檔案進行一次性寫入和迴圈多次讀取的處理過程:
// 建立、寫入方式開啟檔案
CFile file;
file.Open("C://TestFile.txt", CFile::modeWrite | CFile::modeCreate);
// 寫入檔案
memset(WriteBuf, 'a', sizeof(WriteBuf));
file.Write(WriteBuf, sizeof(WriteBuf));
// 關閉檔案
file.Close();
// 只讀方式開啟檔案
file.Open("C://TestFile.txt", CFile::modeRead);
while (true)
{
// 讀取檔案資料
int ret = file.Read(ReadBuf, 100);
……
// 如果到達檔案結尾則中止迴圈
if (ret < 100)
break;
}
// 關閉檔案
file.Close();
Write()和Read()函式執行完後將自動移動檔案指標,因此不必再顯示呼叫Seek()函式去定位檔案指標。包含有檔案定位函式的完整程式碼如下所示:
// 建立、寫入方式開啟檔案
CFile file;
file.Open("C://TestFile.txt", CFile::modeWrite | CFile::modeCreate);
// 寫入檔案
memset(WriteBuf, 'a', sizeof(WriteBuf));
file.SeekToBegin();
file.Write(WriteBuf, sizeof(WriteBuf));
// 關閉檔案
file.Close();
// 只讀方式開啟檔案
file.Open("C://TestFile.txt", CFile::modeRead);
while (true)
{
// 檔案指標
static int position = 0;
// 移動檔案指標
file.Seek(position, CFile::begin);
// 讀取檔案資料
int ret = file.Read(ReadBuf, 100);
position += ret;
……
// 如果到達檔案結尾則中止迴圈
if (ret < 100)
break;
}
// 關閉檔案
file.Close();
補充:
使用CFile類對檔案進行按結構讀取,如:
CFile fileRead,fileWrite;
fileRead.Open(_T("E://a.dat"),CFile::modeRead);//這裡使用巨集_T
fileWrite.Open(_T("E://backup.txt"),CFile::modeCreate | CFile::modeWrite);
fileRead.Read(videoheader,sizeof(VIDEOHEADER));
char buf[sizeof(VIDEOHEADER)*8];
sprintf(buf,"videoheader.cCommandID:%s ,videoheader->cCommandID);通過sprintf對我們需要寫入檔案中的資料進行格式化,這樣在檔案中儲存的資料就是以這裡定義的格式顯示的。
fileWrite.Write(buf,strlen(buf));