天天看點

MFC CFile操作類介紹

CFile檔案操作類

今天看到一篇關于CFile介紹的文章,感覺不錯,分享一下

原文位址:http://www.jizhuomi.com/software/234.html

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++代碼

char writeBuffer[500];     // 要寫入的資料的緩存   
char readBuffer[500];      // 存放讀取資料的緩存   
LONGLONG lOff = 0;         // 檔案指針的偏移量,也是讀取到的資料的總位元組數  
// 構造CFile對象,同時以建立和讀寫的方式打開檔案E:\1.txt   
CFile file(_T("e:\\1.txt"), CFile::modeCreate | CFile::modeReadWrite);   
  
// 将寫入資料的緩存中每個位元組都指派為字元c   
memset(writeBuffer, 'c', sizeof(writeBuffer));   
// 将資料寫入到檔案中   
file.Write(writeBuffer, sizeof(writeBuffer));   
  
while (true)   
{   
    // 以檔案開頭為基準,移動檔案指針到lOff的位置   
    file.Seek(lOff, CFile::begin);   
    // 讀取100個位元組的資料到存放讀取資料的緩存的readBuffer + lOff位置處   
    int nRet = file.Read(readBuffer + lOff, 100);   
    // 根據實際讀取的位元組數,增加檔案指針的移動量   
    lOff += nRet;   
    // 如果讀取資料時傳回值小于指定的100,說明已到檔案尾,跳出循環   
    if (nRet < 100)   
        break;   
}   
  
// 關閉檔案   
file.Close();  
           

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

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

先貼上結構體的定義:

C++代碼

struct student   
{   
    int  nNum;     
    float fScore;   
};  
           

下面是檔案操作的代碼片段:

C++代碼

student s1[2];   // 存放要寫入檔案的資料   
student s2[2];   // 存放從檔案讀取的資料   
CFile file;      // CFile對象   
int nReadBytes = 0;   // 從檔案中讀取到的總位元組數   
  
// 為s1數組各元素指派   
s1[0].nNum = 22;   
s1[0].fScore = 91.5;   
s1[1].nNum = 23;   
s1[1].fScore = 85;   
  
// 以建立、讀寫方式打開檔案E:\1.txt   
if (file.Open(_T("E:\\1.txt"), CFile::modeCreate | CFile::modeReadWrite))   
{   
    // 寫入資料s1結構體數組   
    file.Write(s1, sizeof(s1));   
    // 因為上面調用Write以後檔案指針在檔案尾,是以需要将其移動到檔案開頭   
    file.SeekToBegin();   
  
    while (true)   
    {   
        // 讀取資料到s2   
        int nRet = file.Read((BYTE*)s2 + nReadBytes, sizeof(student));   
        // 計算已經讀取到的總位元組數   
        nReadBytes += nRet;   
        // 如果讀取資料時傳回值小于指定的sizeof(student),則說明已到檔案尾,跳出循環   
        if (nRet < sizeof(student))   
            break;   
    }   
  
    // 關閉檔案   
    file.Close();   
}