慚愧,做了3年多 C++ 了,雖說半路出家,之前也做過 Linux 一年多,但是 MFC 也做了一年多了,由於一直維護公司的老項目,也沒有做過新東西。
最近心血來潮,在網上找了些學習視頻,復習下 MFC 控件的使用,熟悉下 MFC 的 API,畢竟是吃飯的家伙,廢話不多說,來干貨。
最近在仿寫一個記事本軟件,初具基本功能,但遇到了一個比較蹩腳的問題,MFC 在 UNICODE 字符集下在讀取 ANSI 編碼的文本文件時,全中文沒問題,全英文也沒問題,但是中英文混合時,當英文個數為奇數個時,英文后面的漢字就會編程亂碼。
原因是我想的太簡單了,覺得讀取 ANSI 編碼的文本文件,就是讀取多字節字符串,也就有了如下代碼:
代碼中的形參只是定義了一個 CFile 對象並以只讀方式打開,個人習慣,如果解釋就要解釋的明明白白,所以給這兩句代碼也復制過來了。
CFile file;
file.Open(szFile, CFile::modeRead);
1 void CNotepadDlg::ReadAnsi(CFile& file) 2 { 3 file.Seek(0, CFile::begin); 4 char buff[1024]; 5 UINT nRet = 0; 6 CString str; 7 8 while (nRet = file.Read(buff, sizeof(buff - 1))) 9 { 10 buff[nRet] = '\0'; 11 str += buff; 12 } 13 14 SetDlgItemText(IDC_EDIT_TEXT, str); 15 16 }
這只是按照單字節讀取,當然顯示也就存在問題。
這是用微軟記事本打開的 ANSI 編碼的文本文檔。
這是我仿寫記事本打開的文本文檔
結果很明顯,不對。
網上也找了很多處理辦法,A2T,bstr_t,_tsetlocale(LC_ALL, _T("chs")); 這幾個方法都試了,可能我水平不濟,確實沒弄明白,最后還是用最原始的 MultiByteToWideChar() 解決了問題。當然,代碼還存在許多問題,待優化。
1 void CMFC194Dlg::ReadAnsi(CFile& file) 2 { 3 file.Seek(0, CFile::begin); 4 // TODO: 在此處添加實現代碼. 5 char buff[1024]; 6 UINT nRet = 0; 7 CString str; 8 9 LONGLONG nLen = file.GetLength(); 10 char* p = new char[nLen + 1]; 11 nLen = file.Read(p, nLen); 12 p[nLen] = '\0'; 13 TCHAR* pText = new TCHAR[nLen + 2]; 14 memset(pText,0 , nLen + 2); 15 16 nLen = MultiByteToWideChar(CP_ACP, NULL, p, -1, pText, nLen + 2); 17 18 SetDlgItemText(IDC_EDIT_TEXT, pText); 19 20 delete[]p; 21 delete[]pText; 22 }
讀取結果:
處理這個問題的靈魂是這兩句代碼:
TCHAR* pText = new TCHAR[nLen + 2];
memset(pText,0 , nLen + 2);
因為 ANSI 編碼中英文字母占一個字節,中文漢字占兩個字節,所以定義 pText 長度不能是 多字節長度 / 2 + 2,這會導致空間不足,使 MultiByteToWideChar() 返回 0,用 GetLastError() 可知返回122。