(源自:http://blog.csdn.net/suhuaiqiang_janlay/article/details/5963867)
首先,用一個簡單的例子來重現一下我所遇到的問題:
(1)在VS2008的“Property Pages”屬性頁中,選擇“Configuration Properties”-->“General”,可以看到當前使用的字符集是“Multi-Byte Character Set”,也就是說程序中使用的是多字節字符集。
(2)接下來看看ifstream打開txt文件的簡單代碼:
1 #include "stdafx.h" 2 #include <fstream> 3 #include <iostream> 4 using namespace std; 5 int _tmain(int argc, _TCHAR* argv[]) 6 { 7 ifstream infile("d://測試.txt"); 8 if(infile.is_open()) 9 { 10 cout<<"Open Success!"; 11 } 12 else 13 { 14 cout<<"Open Fail!"; 15 } 16 return 0; 17 }
(3)運行結果:輸出“Open Fail” (打開文件失敗!)
從設置選項中可以看到,工程中使用的字符集可設置為“Multi-Byte Character Set”或“Unicode Character Set”,其中“Multi-Byte Character Set”表示使用ANSI編碼方式,“Unicode Character Set”表示使用UNICODE編碼方式。
那么這兩種編碼方式有什么樣的區別呢?
(1)傳統的計算機使用ANSI編碼,在ANSI編碼模式下,英文字符都用1個字節表示,而某些其它國家的文字(如漢字、日文),無法用單個字節來表示,ANSI便采用多個字節來表示這些字符(漢字是2個字節)。
(2)UNICODE包含UTF-8、UTF-16、UTF-32等多種編碼方案(目前windows一般使用UTF-16)。拿UTF-16來說,規定所有字符都使用2個字節表示(不論英文字母還是漢字),對於超出2個字節范圍的字符采用代理(采用4個字節表示)。
UNICODE相比ANSI有很多方面的優勢(優勢體現在哪?),微軟非常提倡使用UNICODE編碼方式,在MS較新版本的系統中都是采用UNICODE編碼的。因此,即便我們在自己寫的程序中使用了ANSI編碼,系統會將其轉換為UNICODE再對其進行處理。
接下來我們說一下ifstream。在調用ifstream的open方法時,系統內部調用mbstowcs_s進行文件名轉換(mbstowcs_s函數的作用是把多字節字符轉化為寬字符),需要注意的是,該函數的調用結果依賴於程序的本地化設置(什么是本地化設置?)。而本地化設置可以通過setlocale函數來設置,譬如:setlocale(LC_ALL, "chinese")表示將程序本身的語言設置為中文,而程序啟動時默認設置為LC_ALL="C"。在使用mbstowcs_s進行字符串轉換時,只有當LC_ALL="chinese"時,含中文的字符串才能正確的轉換成其對應的寬字節字符,否則(在LC_ALL="C"時),漢字會被看成2個單字節的字符,然后再轉換成寬字節的字符,這樣轉換的結果顯然是錯誤的!這就是ifstream打開含中文路徑的文件失敗的原因,因為"d://測試.txt"轉換后得到錯誤的路徑,因此文件打不開!
解決方法如下:
1 /*方法1, 2 使用STL中的locale類的靜態方法指定全局locale 3 使用該方法以后,cout可能不能正常輸出中文,十分蹊蹺 4 我發現了勉強解決的方法:不要在還原區域設定前用cout或wcout輸出中文, 5 否則后果就是還原區域設定后無法使用cout wcout輸出中文 6 */ 7 locale::global(locale(""));//將全局區域設為操作系統默認區域 8 file.open("d://測試//測試文本.txt");//可以順利打開文件了 9 locale::global(locale("C"));//還原全局區域設定 10 cout<<file.rdbuf(); 11 file.close();
1 /* 方法2,使用C函數setlocale,不能用cout輸出中文的問題解決方法同上 */ 2 setlocale(LC_ALL,"Chinese-simplified");//設置中文環境 3 file.open("c://測試//測試文本3.txt");//可以順利打開文件了 4 setlocale(LC_ALL,"C");//還原 5 cout<<file.rdbuf(); 6 file.close();