VS2010/MFC編程入門之四十五(MFC常用類:CFile文件操作類)

上一節中雞啄米講了定時器Timer的用法,本節介紹下文件操作類CFile類的使用。

       CFile類概述

       如果你學過C語言,應該知道文件操作使用的是文件指針,通過文件指針實現對它指向的文件的各種操作。這些文件操作函數中有的最終還是調用了操作系統的API函數或者處理過程與之類似,例如在Windows系統中,fread函數就調用了API函數ReadFile。

       Windows系統的API函數除了ReadFile,還有CreateFile、WriteFile等函數。而MFC基於面向對象的思想,將這些Windows API函數封裝到了CFile類中,實現對文件的打開、關閉、讀、寫、獲取文件信息等操作。使用CFile類對文件進行操作非常便捷。

       CFile類的成員函數

       CFile( );
       CFile(HANDLE hFile);
       CFile(LPCTSTR lpszFileName,UINT nOpenFlags);

       以上三個成員函數都是CFile的構造函數,用於構造CFile對象。參數hFile爲要關聯到CFile對象的文件的句柄。參數lpszFileName爲要關聯到CFile對象的文件的相對路徑或者絕對路徑;參數nOpenFlags爲文件訪問選項的組合,通過各選項的按位或運算實現組合,下面的5個表列出了nOpenFlags參數可能取的選項:

       下面的文件訪問模式選項表中只能選擇一個進行組合,默認取CFile::modeRead。

取值 描述
CFile::modeRead 只讀方式訪問文件
CFile::modeWrite 寫入方式訪問文件
CFile::modeReadWrite 讀寫方式訪問文件

       下面的文件共享模式選項表中也只能選擇一個進行組合,默認的共享模式是CFile::shareExclusive。

取值 描述
CFile::shareDenyNone 允許其他進程對文件進行讀寫
CFile::shareDenyRead 不允許其他進程讀取文件
CFile::shareDenyWrite 不允許其他進程寫文件
CFile::shareExclusive 禁止其他進程對文件的所有訪問

       下面的文件創建模式選項列表中可選擇第一個或兩者都選進行組合。

取值 描述
CFile::modeCreate 如果文件不存在則創建文件,而如果存在則將它關聯到此CFile對象並將長度截取爲0
CFile::modeNoTruncate 如果文件不存在則創建文件,而如果存在則將它關聯到此CFile對象而不進行截取

       注意,選擇CFile::modeNoTruncate時需要與CFile::modeCreate一起使用,即CFile::modeCreate | CFile::modeNoTruncate。

       另外,還有一個文件緩衝選項列表和一個文件安全選項。文件緩衝選項不太常用,雞啄米這裏就不講了,有興趣的可以查閱MSDN。文件安全選項是CFile::modeNoInherit,意爲禁止子進程繼承使用此文件。

       當然,在實際使用時,以上各個表並不是都要用到,大家可以根據自己的需要選擇用哪個表,選擇哪個選項。

       virtual BOOL Open(LPCTSTR lpszFileName,UINT nOpenFlags,CFileException* pError = NULL);

       打開文件。它通常與默認構造函數CFile::CFile()一起使用。參數lpszFileName和nOpenFlags同構造函數。參數pError爲指向文件異常對象的指針,默認爲NULL。

       virtual void Close( );

       關閉文件。如果你沒有在執行析構函數前調用此成員函數關閉文件,則析構函數會爲你關閉。

       virtual UINT Read(void* lpBuf,UINT nCount);

       讀取文件數據到緩存。參數lpBuf是由用戶提供的指向接收文件數據的緩存的指針;參數nCount爲讀取的最大字節數。返回值是實際讀取到緩存的字節數,如果到達文件尾則返回值可能會小於nCount,此時繼續讀取的話,會返回0,所以通常我們都會判斷返回值是否小於nCount或者等於0來確定是否到達文件尾。

       virtual void Write(const void* lpBuf,UINT nCount);

       將緩存中的數據寫入文件。參數lpBuf也是由用戶提供,指向包含寫入數據的緩存的指針;參數nCount爲緩存中要被寫入文件的數據的字節數。

       virtual ULONGLONG Seek(LONGLONG lOff,UINT nFrom);

       在一個打開的文件中重定位文件指針。參數lOff爲文件指針移動的字節個數,爲正數時表示向文件尾移動,爲負數時表示向文件開頭移動;參數nFrom爲lOff的基準位置,即由nFrom位置開始移動lOff個字節,它可以取下面幾個值中的一個:

       CFile::begin       從文件開頭開始移動
       CFile::current    從文件指針的當前位置開始移動 
       CFile::end          從文件尾開始移動

       文件打開時,文件指針被置於0,即文件開頭處。

       如果此函數成功則返回文件指針的位置。

       void SeekToBegin( );

       將文件指針移動到文件開頭。它等價於Seek( 0L, CFile::begin )。

       ULONGLONG SeekToEnd( );

       將文件指針移動到文件末尾。返回值是文件的字節長度。它等價於CFile::Seek( 0L, CFile::end )。

       virtual ULONGLONG GetLength( ) const;

       獲取文件的字節長度。

       virtual void SetLength(ULONGLONG dwNewLen);

       改變文件的長度。參數dwNewLen爲文件的新長度,它可能比文件的當前長度值要大或者小,文件會相應的被擴展或截取。

       virtual CString GetFileName( ) const;

       獲取文件名稱。

       virtual CString GetFilePath( ) const;

       獲取文件的絕對路徑。

       virtual CString GetFileTitle( ) const;

       獲取文件的顯示名稱。舉個例子,與GetFileName區分一下,如果你係統中的文件不顯示擴展名,則它獲取到的文件名稱就不包含擴展名,否則就顯示擴展名。

       virtual ULONGLONG GetPosition( ) const;

       獲取文件指針的當前位置。

       static void PASCAL Remove(LPCTSTR lpszFileName,CAtlTransactionManager* pTM = NULL);

       刪除文件。參數lpszFileName爲要刪除的文件路徑,可以是相對路徑、絕對路徑或者網絡路徑;參數pTM指向一個CAtlTransactionManager對象。

       static void PASCAL Rename(LPCTSTR lpszOldName,LPCTSTR lpszNewName,CAtlTransactionManager* pTM = NULL);

       重命名文件。參數lpszOldName爲老的文件路徑;參數lpszNewName爲新的文件路徑;參數pTM指向一個CAtlTransactionManager對象。實際上此函數的意義已經不只是重命名文件,還可以移動文件到其他目錄下,例如,lpszOldName取"d:\\1.txt",lpszNewName取"e:\\2.txt",這樣可以將D盤中的1.txt文件轉移到E盤並重命名爲2.txt。

       CFile類應用實例

       這裏雞啄米只給大家演示幾個簡單的代碼片段,從這些代碼片段中熟悉CFile類的文件操作。

       實例一:構造CFile對象時就打開文件,然後向文件中寫入數據,最後以Seek函數移動文件指針,讀取文件內容。

C++代碼
  1. char writeBuffer[500];     // 要寫入的數據的緩存   
  2. char readBuffer[500];      // 存放讀取數據的緩存   
  3. LONGLONG lOff = 0;         // 文件指針的偏移量,也是讀取到的數據的總字節數  
  4. // 構造CFile對象,同時以創建和讀寫的方式打開文件E:\1.txt   
  5. CFile file(_T("e:\\1.txt"), CFile::modeCreate | CFile::modeReadWrite);   
  6.   
  7. // 將寫入數據的緩存中每個字節都賦值爲字符c   
  8. memset(writeBuffer, 'c'sizeof(writeBuffer));   
  9. // 將數據寫入到文件中   
  10. file.Write(writeBuffer, sizeof(writeBuffer));   
  11.   
  12. while (true)   
  13. {   
  14.     // 以文件開頭爲基準,移動文件指針到lOff的位置   
  15.     file.Seek(lOff, CFile::begin);   
  16.     // 讀取100個字節的數據到存放讀取數據的緩存的readBuffer + lOff位置處   
  17.     int nRet = file.Read(readBuffer + lOff, 100);   
  18.     // 根據實際讀取的字節數,增加文件指針的移動量   
  19.     lOff += nRet;   
  20.     // 如果讀取數據時返回值小於指定的100,說明已到文件尾,跳出循環   
  21.     if (nRet < 100)   
  22.         break;   
  23. }   
  24.   
  25. // 關閉文件   
  26. file.Close();  

       實際上,在Write函數和Read函數執行後,文件指針會自動移動到最後操作的位置,所以其實上面的代碼中無須使用Seek函數再去手動移動文件指針。這將在下面的實例二中體現出來。

       實例二:構造CFile對象,然後使用Open成員函數打開文件,再寫入一個結構體數組,最後讀取出來。

       先貼上結構體的定義:

C++代碼
  1. struct student   
  2. {   
  3.     int  nNum;     
  4.     float fScore;   
  5. };  

       下面是文件操作的代碼片段:

C++代碼
  1. student s1[2];   // 存放要寫入文件的數據   
  2. student s2[2];   // 存放從文件讀取的數據   
  3. CFile file;      // CFile對象   
  4. int nReadBytes = 0;   // 從文件中讀取到的總字節數   
  5.   
  6. // 爲s1數組各元素賦值   
  7. s1[0].nNum = 22;   
  8. s1[0].fScore = 91.5;   
  9. s1[1].nNum = 23;   
  10. s1[1].fScore = 85;   
  11.   
  12. // 以創建、讀寫方式打開文件E:\1.txt   
  13. if (file.Open(_T("E:\\1.txt"), CFile::modeCreate | CFile::modeReadWrite))   
  14. {   
  15.     // 寫入數據s1結構體數組   
  16.     file.Write(s1, sizeof(s1));   
  17.     // 因爲上面調用Write以後文件指針在文件尾,所以需要將其移動到文件開頭   
  18.     file.SeekToBegin();   
  19.   
  20.     while (true)   
  21.     {   
  22.         // 讀取數據到s2   
  23.         int nRet = file.Read((BYTE*)s2 + nReadBytes, sizeof(student));   
  24.         // 計算已經讀取到的總字節數   
  25.         nReadBytes += nRet;   
  26.         // 如果讀取數據時返回值小於指定的sizeof(student),則說明已到文件尾,跳出循環   
  27.         if (nRet < sizeof(student))   
  28.             break;   
  29.     }   
  30.   
  31.     // 關閉文件   
  32.     file.Close();   
  33. }  

       本節內容就到這裏,如果有其他語言的文件操作的經驗的話,應該還是比較簡單的。雞啄米很高興能在大家的編程入門之路上貢獻自己一點微薄的力量。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章