本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《 阿里云开发者社区用户服务协议 》和 《 阿里云开发者社区知识产权保护指引 》。如果您发现本社区中有涉嫌抄袭的内容,填写 侵权投诉表单 进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。
碰到的问题: 今天碰到这个问题了,是在使用Crypto++库的时候遇到的,该库操作文件是使用的std::ifstream。在我给文件生成签名的时候,每每碰到中文路径名就出错,后来跟进库代码一看是打开文件的时候出错。 据说这个问题在VS2003以及之前版本是没有的,不幸的是我现在用的是VS2005的版本。 产生问题的原因: 究竟是因为什么产生的这个问题呢?如果你跟进去VC实现版的STL代码,你会发现,它有一个将传入的char字符串文件名转换为UNICODE的wchar_t字符串这样一个过程,其代码如下: None.gif _Fiopen( const char *filename, None.gif ios_base::openmode mode, int prot) { // open wide-named file with byte name
InBlock.gif
wchar_t wc_name[FILENAME_MAX];
InBlock.gif
InBlock.gif
InBlock.gif if (mbstowcs_s(NULL, wc_name, FILENAME_MAX, filename, FILENAME_MAX - 1) != 0)
InBlock.gif return (0);
InBlock.gif return _Fiopen(wc_name, mode, prot);
ExpandedBlockEnd.gif }
wbstowcs_s方法最终进入到了_mbstowcs_l_helper方法, 如果得到的是C locale,则它认为传进来的字符串为ASCII码,也就是单字节字符,它仅仅是进行了char到wchar_t指针的转换而已,那很显然第二个字节肯定为零,自然的字符就错了; 如果不是的话,它认为是多字节字符,将会调用MultiByteToWideChar进行转码。 在VC8里面,local默认是C locale,所以就出错了。以下为摘抄的该段代码: if (_loc_update.GetLocaleT()->locinfo->lc_handle[LC_CTYPE] == _CLOCALEHANDLE) {
ExpandedSubBlockStart.gif /* C locale: easy and fast */
InBlock.gif while (count < n)
ExpandedSubBlockStart.gif {
InBlock.gif *pwcs = (wchar_t) ((unsigned char )s[count]);
InBlock.gif if (!s[count])
InBlock.gif return count;
InBlock.gif count++;
InBlock.gif pwcs++;
ExpandedSubBlockEnd.gif }

InBlock.gif return count;
InBlock.gif
ExpandedBlockStart.gif }
{
InBlock.gif int bytecnt, charcnt;
InBlock.gif unsigned char *p;
InBlock.gif
ExpandedSubBlockStart.gif /* Assume that the buffer is large enough */
InBlock.gif if ( (count = MultiByteToWideChar( _loc_update.GetLocaleT()->locinfo->lc_codepage,
InBlock.gif MB_PRECOMPOSED |
InBlock.gif MB_ERR_INVALID_CHARS,
InBlock.gif s,
InBlock.gif -1,
InBlock.gif pwcs,
InBlock.gif ( int )n )) != 0 )
ExpandedSubBlockStart.gif return count - 1; /* don't count NUL */
知道了问题的缘由,才能够更好的解决问题。在VC6和VC7都没有经过这个步骤,好像是直接调用的SDK的CreateFile方法,因此就没有问题。而VC8这样根据locale来转码所以造成了问题。

解决办法:
1、使用C语言的函数设置为中文运行环境

None.gif setlocale(LC_ALL, "Chinese-simplified");

其中参数一有以下几个值:

/* Locale categories */ 经过了我的测试,两种方法都是可用的。 但是,接着又有问题出现了,std::cout输出中文时候,中文是输出不了的!这可真是令人烦扰了。要解决这个问题那么就只能是将代码页再设置回去了,用以下方法可以很好解决问题。 设置代码页为简体中文,936是简体中文的代码页。
None.gif
std::locale loc1 = std::locale::global(std::locale(".936")); {
InBlock.gif // 在这里使用std::ifstream 或者 std::fstream dot.gif
ExpandedBlockEnd.gif
}