之前我转载过一篇ofstream和wofstream与中文输出问题,让我初步知道如何解决这类问题。第一次我没有在意,按照文章中做的方法去做,然后程序就运行正常了。我试图去记住这些规则,但是我后来发现,太难了。以至于我在最近一次使用到 std::wofstream 类的时候,发现我无法往其中输入unicode字符。让我找了几个小时的bug,于是我今天就花了两个小时,在网上搜索资料,以及自己写一些测试工程,调试跟踪 std::wofstream 的相关函数,差不多明白了原因。下面让我用最简单的方式,让你真正理解,wofstream,wcout无法输出unicode字符的原因。
- 首先visual studio(也可以说微软)版本的 wofstream,wcout最终输出的字符编码都是ANSI(多字节编码,MultiByte)。例如:
std::wofstream fOut; fOut.open( L"你好1.txt", std::ios::trunc ); fOut << L"徐杰" << std::endl; fOut.close();
这样简短的代码,最后输出的文件编码方式是:ANSI。这也是最令我吃惊的。因为我以为 wofstream 比 ofstream 多一个 w,意思是可以直接写入unicode字符(宽字符,wide-char)。但实际上,多一个 w 只是表明其支持 unicode 文件名(或者说全路径文件名)。
- wofstream,wcout 在处理 unicode字符 时,必须进行内部编码转换(unicode -> ansi )。
看完第一点之后,第二点是很自然的,因为 wofstream,wcout 最后都是要输出 ansi 的,所以必须进行字符编码转换。
- wofstream,wcout(或者说C++)进行编码转换的时候,需要知道将 unicode 转换到哪个国家的 ansi 编码(code page )。
code page 的信息存放在 locale 的 codecvt 里面。 C++ 默认的 locale 中的 codecvt 没有保存任何国家的 code page。所以此时调用wofstream << L"徐杰";
- std::locale( std::locale(),"",std::locale::ctype )会创建当前系统环境下locale,这个locale中会保存这个系统 ansi 使用 code page。
std::locale oNewLocale( std::locale(),"",std::locale::ctype ); std::locale oPreviousLocale = std::locale::global( oNewLocale ); //...文件打开,保存信息,关闭文件等操作。 std::locale::global( oPreviousLocale );
所以我们使用时,先将本地locale设置上去,然后用完之后,在设置回来(以免影响到其他系统的使用)。locale 类的相关用法请参考相关的C++标准。也可参考此链接:locale使用说明
知道原因之后,你可以更自如的选择使用 wofstream, ofstream, wcout, cout了。