1. 程式人生 > >MFC中的檔案讀寫方法總結

MFC中的檔案讀寫方法總結

CStdioFile繼承自CFile,一個CStdioFile 物件代表一個用執行時函式fopen 開啟的C 執行時流檔案。
      流式檔案是被緩衝的,而且可以以文字方式(預設)或二進位制方式開啟。文字方式提供對硬回車—換行符對的特殊處理。當你將一個換行符(0x0A)寫入一個文字方式的CStdioFile 物件時,位元組對(0x0D,0x0A)被髮送給該檔案。當你讀一個檔案時,位元組對(0x0D,0x0A)被翻譯為一個位元組(0x0A)。    CStdioFile 不支援DuplicateLockRange,和UnlockRange 這幾個CFile 函式。如果在CStdioFile 中呼叫了這幾個函式,將會出現CNoSupported 異常。 
CStdioFile::ReadString(LPTSTR lpsz, UINT nMax); 
  讀取一行文字到緩衝區,遇到“0x0D,0x0A”時停止讀取,並且去掉硬回車“0x0D”,保留換行符“0x0A”,在字串末尾新增“/0”(0x00)。nMax個字元裡包含0x00這個字元。分析如下:    1)如果nMax <= 字元數,讀取(nMax-1)個字元 + 0x00    2)如果nMax = 字元數 + 1,讀取nMax個字元 + 0x00    3)如果nMax > 字元數,讀取字元數 + 0x0A + 0x00 
CStdioFile::ReadString(CString &rString);(過載) 
  讀取一行文字到rString,遇到回車換行符停止讀取。回車和換行符不讀到rString,而且末尾也沒有新增“/0”
。 
CStdioFile::WriteString( LPCTSTR lpsz );(不支援CString直接寫入) 
  將一個緩衝區中的資料寫入與CStdioFile 物件關聯的檔案中。結束的空字元(“/0”)不被寫入該檔案。lpsz 中的所有換行符都被以一個硬回車換行符對寫入該檔案,即“/n”被轉化成“/r/n”寫入到檔案裡。    CFile的派生類CStdioFile提供了對檔案進行流式的操作功能。其中函式void CStdioFile::WriteString( LPCTSTR lpsz )寫入一個字串,需要給字串lpsz的末尾加上換行標誌”/r/n”;函式bool CStdioFile::ReadString(CString &rString )從檔案中讀取一行,如果檔案未讀完返回true,否則返回false。        當CStdioFile.WriteString無法處理中文時,把工程的字符集屬性 改成 使用多位元組字符集
 就可以了,具體設定方法如:開啟專案屬性-->配置屬性-->常規-->字符集-->改成 使用多位元組字符集     要注意的是CStdioFile在_MSBC環境下讀取任何ANSI文字資料都沒問題,在UNICODE環境下讀取ANSI文字中的中文時就會顯示亂碼。其原因是由於CStdioFile 讀取ANSI文字資料時按char型別讀取,在_MSBC下可以直接填充到CString,在UNICODE環境下要先將char轉換成寬字元 WCHAR,然後再填充到CString,即一個漢字的兩個char將變成兩個UNICODE字元WCHAR。那麼問題如何解決呢?實際上在UNICODE環境下,file.ReadString(strLine)取得的資料是char型別,但是儲存在UNICODE字串中。為了取得真實資料,必須對strLine進行處理。

  在CFile類中提供了2種模式,typeBinary和typeText。如果是CTextFile類的話當然要強制使用typeText型別了。那麼CStdioFile是怎麼做的呢?         
BOOL CStdioFile::Open(LPCTSTR lpszFileName, UINT nOpenFlags, CFileException* pException)
{
   …
   /// 呼叫基類開啟檔案,注意通過nOpenFlags & ~typeText過濾了檔案的文字屬性
   if (!CFile::Open(lpszFileName, (nOpenFlags & ~typeText), pException))
   return FALSE;
   …
  ///轉換找開模式
  if (nOpenFlags & typeBinary)
   szMode[nMode++] = 'b', nFlags ^= _O_TEXT;
   else
   szMode[nMode++] = 't';
   …
   // open a C-runtime low-level file handle
   int nHandle = _open_osfhandle((UINT_PTR) m_hFile, nFlags);
   // open a C-runtime stream from that handle
   if (nHandle != -1)
   m_pStream = _fdopen(nHandle, szMode);
   …
}

   由上面的程式碼可以看出,CStdioFile強制過濾了typeText標誌,使得檔案開啟模式可以是二進位制模式。這已經可以證明CStdioFile不是一個純粹TextFile類。    再仔細看上面的程式碼,在呼叫基類開啟後,又使用_open_osfhandle和_fdopen做了奇怪的轉換,察看m_pStream的型別  FILE* m_pStream;// stdio FILE
   這是一個標準I/O的FILE結構。如果再進一步的研究CStdioFile的原始碼,還會發現它都是呼叫標準I/O的函式來操作的,比如用_fputts/_fgetts來實現WriteString/ReadString,用fread/fwrite/fseek來替代Read/Write/Seek。注意CStdioFile並沒有使用CFile的Read/Write/Seek函式,如果在Open裡將使用fopen直接開啟的話,CStdioFile甚至可以說和CFile沒有任何的關係。,由此這個類叫做CStdioFile就不奇怪了。    為什麼要研究這個問題呢?前一段在csdn.net上看到不少人問為什麼UNICODE的文字檔案處理出現亂碼?他們很驚異發現平常作為TextFile的處理類用得CStdioFile竟然失效了。真的是它失效了嗎?其實是標準的I/O操作並不支援UNICODE的模式而已。