最近维护一个项目,遇到了ifstream在中文路径下打开文件失败的bug,我搜索了一下,最后整理成下文以后日后查阅。

一、问题重现

  1. vs2008下创建一个简单win32工程。
  2. 使用ANSI编码方式:项目属性页 ->配置属性 ->常规 ->项目默认值 ->字符集中选择"使用多字节字符集"。
  3. 简单出错代码:
    #include "stdafx.h"
    #include <Windows.h>
    #include <fstream> int _tmain(int argc, _TCHAR* argv[])
    {
    std::ifstream infofile;
    infofile.open(_T("D:\\测试\\test.cpp"));
    if (infofile.is_open())
    {
    printf("Open success!!!\r\n");
    }
    else
    {
    printf("Open fail error code:%d\r\n", GetLastError());
    }
    return 0;
    }

  4. 运行输出结果:Open fail error code:3。
  5. GetLastError()错误代码:3   系统找不到指定的路径; 而选择“使用 Unicode 字符集”时则无此问题出现;说明 是字符编码的问题,ifstream的open方法对传进入的中文窄字符处理可能存在问题。

二、原因分析

  1. 跟进ifstream的open方法可以发现,在其内部是用mbstowcs_s来实现窄字符转化成宽字符的。

  2. msdn:mbstowcs_s uses the current locale for any locale-dependent behavior (mbstowcs_s的调用结果依赖于程序的本地化设置)。
  3. 本地化设置可以通过setlocale函数来设置,例如:setlocale(LC_ALL, "chinese")表示将程序本身的语言设置为中文,而程序启动时默认设置为LC_ALL="C"。
  4. 在使用mbstowcs_s进行字符串转换时,只有当LC_ALL="chinese"时,含中文的字符串才能正确的转换成其对应的宽字节字符,否则(在LC_ALL="C"时),汉字会被看成2个单字节的字符,然后再转换成宽字节的字符,这样转换的结果显然是错误的!
  5. 这就是ifstream打开含中文路径的文件失败的原因,因为"D:\\测试\\test.cpp"转换后得到错误的路径,所以找不到指定路径!

三、解决方法

  1. 最好的方法就是使用“使用 Unicode 字符集”,因为不但可以避免此类问题,而且也提升的程序执行效率(系统底层都是使用宽字节的 window 核心程序有说)

  2. 如果是历史项目不方便大改的话,可以有以下两种方法实现,展示代码如下:
    	std::ifstream infofile;
    // 方法1,使用STL中的locale类的静态方法指定全局locale
    std::locale::global(std::locale("")); //将全局区域设为操作系统默认区域
    infofile.open("D:\\测试\\test.cpp"); //可以顺利打开文件了
    std::locale::global(std::locale("C")); //还原全局区域设定 // 方法2,使用C函数setlocale
    TCHAR* ptOldLocale = _tcsdup(_tsetlocale(LC_CTYPE, NULL)); //获取本地语言保存
    _tsetlocale(LC_CTYPE, _T("")); //C语言的全局locale设置为本地语言,但这会导致cout和wcout不能输出中文
    infofile.open("D:\\测试\\test.cpp"); //可以顺利打开文件了
    _tsetlocale(LC_CTYPE, ptOldLocale); //将C语言的全局locale恢复

ifstream中文路径问题分析的更多相关文章

  1. 浅析GDAL库C#版本支持中文路径问题

    GDAL库对于C#的支持问题还是蛮多的,对于中文路径的支持就是其中之一(另一个就是通过OGR库获取图形的坐标信息). 关于C#支持中文路径,看过我之前博客的应该都不陌生,如果使用的是我修改过的GDAL ...

  2. GDAL打开HDF格式时遇到的中文路径问题(未解决)

    众所周知,中文环境下(VS2010 C++工程编码为多字节编码),在使用1.8.0版本以后的GDAL打开中文路径下的影像文件(如GeoTiff文件)时, 需对中文文件路径做特殊处理,有2种方法:(我使 ...

  3. QGis、Gdal本地中文路径问题

    编译qgis完整项目后,由于Gdal库的原因,中文路径下通过添加矢量数据中数据库中是没有OGR的Oracle数据库功能的: 最开始打算通过重新编译gadl库从内部支持中文的(有成功的麻烦也请告诉我), ...

  4. CentOS个人目录下中文路径转英文路径

    CentOS个人目录下中文路径转英文路径 如果安装了中文版到CentOS之后,root目录及home目录下会出现中文到路径名,如"桌面"."文档"," ...

  5. Atitit.url 汉字中文路径  404 resin4 resin  解决  v2 q329

    Atitit.url 汉字中文路径  404 resin4 resin  解决  v2 q329 1. Pluginx机制1 2. Code1 3. 参考4 1. 原理 过滤器  ,,拦截jpg  w ...

  6. 解决ckeditor中文路径无法下载,无法显示图片问题

    使用ckfinder上传的文件如果是中文路径,下载的时候会找不到 假如使用tomcat服务器,找到tomcat目录>conf文件夹的server.xml>用查找找到Connector这个 ...

  7. 解决 git 中文路径显示 unicode 代码的问题

    解决 git 中文路径显示 unicode 代码的问题 当被修改的文件中带有中文字符时,中文字符会被转换为 unicode 代码,看不出原来的文件名. 这时,只要配置 :: git config -- ...

  8. 关于 MAXScript 中文路径返回上级目录(精简版)

    之前写过一个 关于 MAXScript 中文路径返回上级目录 的博文 今天无意中发现了一个更简单的方法 代码如下: fn newfile filepath = ( nf = getfilenamepa ...

  9. struts2中form提交到action中的中文参数乱码问题解决办法(包括取中文路径)

    我的前台页是这样的: <body>      <form action="test.action" method="post">     ...

随机推荐

  1. mysql索引之唯一索引

    mysql 的唯一索引一般用于不重复的字段,一般会把表中的id设为唯一索引,创建唯一索引的目的不是为了提高查询速度,而是为了避免数据重复,注意:唯一索引可以有多个,但是列值必须唯一,创建唯一索引使用关 ...

  2. php 之 房屋租赁练习(0509)

    做出以下页面并实现其对应的功能: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "h ...

  3. js获取下拉列表(select)选中项的值和文本

    获取下拉列表选中项的值和文本(select) <html> <head> <meta charset="utf-8"/> <title&g ...

  4. C程序设计语言练习题1-8

    练习1-8 编写一个统计空格.制表符与换行符个数的程序. 代码如下: #include <stdio.h> // 包含标准库的信息. int main() // 定义名为main的函数,它 ...

  5. Selenium2Library关键字

    对Selenium2Library关键字的整理和翻译.英文不好,仅供参考. 1.Add Cookie [ name | value | path=None | domain=None | secure ...

  6. bzoj 2075: [POI2004]KAG

    整天鬼畜题搞搞,感觉药丸…… 这种题出到xjoi模拟题里,太神了…… 这题的核心在于分割Cograph,尝试把Cograph的合成过程给求出来. 我们将这张图中的边为黑边,在这张图的补图中出现的边为白 ...

  7. [转]RegOpenKeyEx函数失败的问题

    在使用这个函数RegOpenKeyEx的时候,老是执行不成功,函数本身返回2,GetLastError返回0.在CSDN上查阅资料说是返回2的原因是注册表中对应路径不存在,可是我电脑中注册表那个键值明 ...

  8. 初识Mybatis框架,实现增删改查等操作

    此第一次接触Mybatis框架确实是有点不适应,特别是刚从Hibernate框架转转型过来,那么为什么要使用Mybatis框架,Mybatis框架和Hibernate框架又有什么异同呢? 这个问题在我 ...

  9. 奇葩的SQL*Net more data from client等待,导致批处理巨慢

    <pre name="code" class="sql"><pre name="code" class="sql ...

  10. linux/unix 段错误捕获【续】

    本文为“在C/C++中捕获段错误,打印出错的具体位置”的续篇,进一步解决涉及动态链接库的情况.   背景知识: ·linux/unix下动态链接库的基本原理 ·/proc/pid/maps文件的基本格 ...