关于std::fstream以及std::ifstream打开中文路径名失败的问题和解决方法

碰到的问题:
      今天碰到这个问题了,是在使用Crypto++库的时候遇到的,该库操作文件是使用的std::ifstream。在我给文件生成签名的时候,每每碰到中文路径名就出错,后来跟进库代码一看是打开文件的时候出错。
据说这个问题在VS2003以及之前版本是没有的,不幸的是我现在用的是VS2005的版本。

产生问题的原因:
    究竟是因为什么产生的这个问题呢?如果你跟进去VC实现版的STL代码,你会发现,它有一个将传入的char字符串文件名转换为UNICODE的wchar_t字符串这样一个过程,其代码如下:

_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);
    }

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)
        {
            /* C locale: easy and fast */
            while (count < n)
            {
                *pwcs = (wchar_t) ((unsigned char)s[count]);
                if (!s[count])
                    return count;
                count++;
                pwcs++;
            }
            return count;

        } else {
            int bytecnt, charcnt;
            unsigned char *p;

            /* Assume that the buffer is large enough */
            if ( (count = MultiByteToWideChar( _loc_update.GetLocaleT()->locinfo->lc_codepage,
                                               MB_PRECOMPOSED |
                                                MB_ERR_INVALID_CHARS,
                                               s,
                                               -1,
                                               pwcs,
                                               (int)n )) != 0 )
                return count - 1; /* don't count NUL */

知道了问题的缘由,才能够更好的解决问题。在VC6和VC7都没有经过这个步骤,好像是直接调用的SDK的CreateFile方法,因此就没有问题。而VC8这样根据locale来转码所以造成了问题。

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

setlocale(LC_ALL, "Chinese-simplified");

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

/* Locale categories */

#define LC_ALL          0
#define LC_COLLATE      1
#define LC_CTYPE        2
#define LC_MONETARY     3
#define LC_NUMERIC      4
#define LC_TIME         5

#define LC_MIN          LC_ALL
#define LC_MAX          LC_TIME

这些值的意义可以在MSDN当中查到。
从上面所贴出来的代码可以知道wbstowcs_s方法依赖着locale的LC_CTYPE分类的数值。

2、使用STL函数设置为系统语言环境

std::locale::global(std::locale(""));
建议用这个方法,因为更C++一些,而且可以很容易的恢复之前的locale,以下会说到这个。

最终的解决方法:
经过了我的测试,两种方法都是可用的。
但是,接着又有问题出现了,std::cout输出中文时候,中文是输出不了的!这可真是令人烦扰了。要解决这个问题那么就只能是将代码页再设置回去了,用以下方法可以很好解决问题。

    //设置代码页为简体中文,936是简体中文的代码页。
    std::locale loc1 = std::locale::global(std::locale(".936"));
{
    // 在这里使用std::ifstream 或者 std::fstream


    //恢复原来的代码页
    std::locale::global(std::locale(loc1));
这个恐怕是我现在能够得到的最佳方法了。

时间: 2024-12-01 02:46:16

关于std::fstream以及std::ifstream打开中文路径名失败的问题和解决方法的相关文章

Win8系统下打开网页总是出现未响应的解决方法

  我们使用电脑的用途中,最常见的估计是浏览网页了,不管是查找资料.搜索视频.还是阅读微博,都需要打开浏览器,所以浏览器对于我们来说是很重要的存在,几乎每个人的电脑中都有至少一个浏览器,但是最近有用户反映说使用win8系统打开浏览器的时候,会出现卡死的现象,浏览器也没有任何的反应,这种现象很影响我们的正常使用,下面小编就来教大家Win8打开网页总是未响应怎么办? Win8系统下打开网页总是出现未响应的解决方法 1.首先打开IE浏览器,然后点击菜单栏上方的"菜单---Internet选项"

Win7系统使用IE浏览器弹出“无法打开internet站点 已终止操作”的解决方法

  windows操作系统内置有IE浏览器,也是我们使用的最多次的浏览器之一了,但有时win7纯净版系统在使用IE浏览器过程中,也会遇到各种问题.比如最近我们打开网页时,会弹出一个提示框"Internet Explorer无法打开Internet 站点about:blank.已终止操作",遇到这样问题该如何解决呢?带着此问题,下面小编和大家分享具体的解决方法. 方法如下: 一.重置IE 方法原理:重置IE,把篡改的错误设置全部清除,恢复干净的IE设置. 注意事项:重置IE后,里面的有部

FastReport 4.13.1 中文菜单显示不全或者乱码解决方法

FastReport 4.13.1 中文菜单显示不全或者乱码解决方法 FastReport 4.13.1 中文菜单显示不全或者乱码解决方法: 可以自己编译一个frcc.exe,替换Res目录下的,然后再recompile即可.   delphi xe3测试界面都正常. 用delphi xe3建立一个console工程,名称为frcc,代码如下: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28

Servlet输出中文乱码的问题之Filter解决方法

Servlet输出中文乱码的问题之Filter解决方法 Filter过滤器的代码如下: package filter; import java.io.IOException; import java.util.Collection; import java.util.Iterator; import java.util.Map; import java.util.Set; import javax.servlet.Filter; import javax.servlet.FilterChain;

按ctrl+space无法在中文与英文之间切换的解决方法

  近日小编的电脑系统重装了,安装上搜狗拼音输入法后,使用以前常用按键"ctrl+space"切换中英文输入法状态,发现无法切换到英文输入状态. 小编从网上寻找解决方法时,发现很多网友都遇到这个问题,网上的解决方法都不能解决问题,于是小编,决定自己寻找解决方法. 终于发现小编按ctrl+space无法在中文与英文之间切换的原因:小编电脑上的输入法只有搜狗拼音输入法一种,没有英文输入法,当然无法进行正常中英文切换了.相信很多网友都遇到类似的问题,是因为自己的输入法设置中没有添加英文输入法

打开outlook时提示Invalid XML的解决方法

症状:同事的Outlook出问题,首先提示是ost文件崩溃,重建ost后打开outlook,提示:Cannot start Microsoft office outlook, cannot open the outlook window. Invalid XML, the view cannot be loaded. 原因:未明 解决方法:打开运行,输入:Outlook.exe /resetnavpane,成功启动outlook,关掉再开,一切正常. 查看本栏目更多精彩内容:http://www

禁用工行加载后打开IE9总是弹出提示的解决方法

为了不影响IE浏览器打开的速度,一般情况我们会把一些不经常用的IE加载项给禁用了,等到需要的时候在启动.但是如果你安装了工商银行网上银行加载项,那么你就悲剧了. 该加载项启动占用时间太长就算了,想着那就暂时先禁用他吧.然后打开"工具"-> "管理加载项",在里面找到 ICBC Anti-Phishing class 加载项将其禁用,以为至此就OK了. 无奈以后每次启动IE9的时候,他都会弹出"ICBC Anti-Phishing class"

Win8系统打开主题提示MadobeYu.deskthemepack无效的解决方法

  1.首先打开控制面板:更改日期.时间或数字格式点击进入区域; 主题提示MadobeYu.deskthemepack无效的解决方法-deskthemepack"> 2.接着选择区域三个选项中的管理:然后选择Unicode区域改成日语,位置也改成日本; 3.然后重启电脑,再次进入后我的metro界面没了磁贴.然后安装主题吧.最后在改成中国再重启下就行了.

Win8系统在同一个窗口不能打开新文件夹的三种解决方法

  Win8系统同时打开多个文件夹,他们会叠加在同一个窗口.但是有的用户在却不能在同一窗口打开多个文件夹.已经打开一个Win8文件夹的情况下,就不能在同一个窗口打开新的文件夹了,这个时候应该怎么办呢? 方法一: 1.Win+R调出运行 ,输入"regedit"回车或确定打开注册表; 2.然后找到注册表这一项:HKEY_CLASSES_ROOTDirectoryshell 3.将值改为none; 方法二: 1.Win+R调出运行,输入sfc /scannow 让系统自动运行,修复; 2.