setlocale 与 mbstowcs 的问题(转载)

出处:http://blog.sina.com.cn/s/blog_55c1b83b0100wbah.html

1 问题
在 Windows XP 多语言简中环境下,用 VC2005 中的 std::fstream 打开中文名文件,系统报错找不到此文件。

std::ifstream file("\xd6\xd0.txt"); // GBK 编码的 "中.txt" if (!file) { std::cerr << "Cannot open file!"; // Oops! }

2 原因
在 VC2005 中 std::fstream 的打开文件的函数实现里,传入的 char const* 文件名作为多字节首先被 mbstowcs 转换成宽字节后,再转发给 Unicode 版本的 API 进行实际的打开文件操作。见 fiopen.cpp:


_MRTIMP2_NCEEPURE FILE *__CLRCALL_PURE_OR_CDECL _Fiopen(const char *filename, ios_base::openmode mode, int prot) { // open wide-named file with byte name wchar_t wc_name[FILENAME_MAX];   if (mbstowcs_s(NULL, wc_name, FILENAME_MAX, filename, FILENAME_MAX - 1) != 0) return (0); return _Fiopen(wc_name, mode, prot); }

问题的关键在于,对于 mbstowcs 函数来说,它需要知道多字节的编码类型才能正确的将其转换成宽字节的 unicode,很可惜这个编码类型并没有体现在函数的参数列表里,而是隐含依赖全局的 locale 。更加不幸的是,全局 locale 默认没有使用系统当前语言,而是设置为没什么用处的 “C” locale 。于是 GBK 编码的文件名在 “C” locale 下转换错误,悲剧发生了……

3 解
知道了原因,解就很简单了。在调用 mbstowcs 或使用它的函数之前,先用 setlocale 将全局默认 locale 设为当前系统默认 locale :setlocale(LC_ALL, "");
如果是在非中文系统上转 GBK 编码,就需要指定中文 locale :
setlocale(LC_ALL, "chs"); // chs 是 VC 里简中的 locale 名字
还有一种方法,直接使用宽字节版本的API,之前的编码由自己转换好,避免系统语言环境设置的影响。在 VS2005 中 fstream 有个扩展,可以直接打开宽字节文件名:

std::ifstream file(L"\u4E2D.txt"); // UCS2 编码的“中.txt”
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值