項目編譯后給朋友試運行,發(fā)現(xiàn)運行出錯,提示路徑不正確找不到配置文件。因為朋友是放在桌面運行的,于是推測是中文路徑的問題(因為路徑中包含"桌面"兩個漢字)。反應(yīng)很詫異,什么年代了,還有中文路徑的問題...
跟蹤了一下ifstream的open函數(shù),發(fā)現(xiàn)ifstream在打開文件之前會通過_mbstowcs_l_helper函數(shù)把文件路徑從mutilbyte轉(zhuǎn)換到unicode。其中的關(guān)鍵轉(zhuǎn)換函數(shù)如下:
if (_loc_update.GetLocaleT()->locinfo->lc_handle[LC_CTYPE] == _CLOCALEHANDLE)
{
/* C locale: easy and fast */
while (count < n)
{
*pwcs = (wchar_t) ((unsigned char)s[count]);
if (!s[count])
return count;
count++;
pwcs++;
}
return count;
}
而vc的默認(rèn)local信息就是
_CLOCALEHANDLE,于是中文字符很悲劇的被轉(zhuǎn)換成了莫名其妙的一串東西。google了下,似乎很多人碰到了這個問題,也沒有特別好的解決方案,要不直接unicode,要不每次調(diào)用fstream前后都調(diào)用一遍setlocal,對代碼的侵入性都很強(qiáng)。
我做了個封裝的解決方案,使用個模板類對fstream做一個wrapper,代碼如下:
template<class T>
struct fstream_fix
:public T
{
fstream_fix(){};
template<class T1>
fstream_fix(T1 v1){
setlocale(LC_CTYPE, ".936");
T::open(v1);
setlocale(LC_CTYPE, 0);
}
template<class T1,class T2>
fstream_fix(T1 v1,T2 v2){
setlocale(LC_CTYPE, ".936");
T::open(v1,v2);
setlocale(LC_CTYPE, 0);
}
template<class T1>
void open(T1 v1){
setlocale(LC_CTYPE, ".936");
T::open(v1);
setlocale(LC_CTYPE, 0);
}
template<class T1,class T2>
void open(T1 v1,T2 v2){
setlocale(LC_CTYPE, ".936");
T::open(v1,v2);
setlocale(LC_CTYPE, 0);
}
};
#define ifstream fstream_fix<ifstream>
#define ofstream fstream_fix<ofstream>
OK.完美,對原項目沒有任何影響,ifstream fi(filepath);filepath中含有中文也能正常工作了。:) 當(dāng)然要注意的是,在宏定義之后,就不能再include <fstream>,不然可能會有編譯錯誤。