ifstream中文路径问题分析
最近维护一个项目,遇到了ifstream在中文路径下打开文件失败的bug,我搜索了一下,最后整理成下文以后日后查阅。
一、问题重现
- vs2008下创建一个简单win32工程。
- 使用ANSI编码方式:项目属性页 ->配置属性 ->常规 ->项目默认值 ->字符集中选择"使用多字节字符集"。
- 简单出错代码:
#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;
} - 运行输出结果:Open fail error code:3。
- GetLastError()错误代码:3 系统找不到指定的路径; 而选择“使用 Unicode 字符集”时则无此问题出现;说明 是字符编码的问题,ifstream的open方法对传进入的中文窄字符处理可能存在问题。
二、原因分析
- 跟进ifstream的open方法可以发现,在其内部是用mbstowcs_s来实现窄字符转化成宽字符的。
- msdn:mbstowcs_s uses the current locale for any locale-dependent behavior (mbstowcs_s的调用结果依赖于程序的本地化设置)。
- 本地化设置可以通过setlocale函数来设置,例如:setlocale(LC_ALL, "chinese")表示将程序本身的语言设置为中文,而程序启动时默认设置为LC_ALL="C"。
- 在使用mbstowcs_s进行字符串转换时,只有当LC_ALL="chinese"时,含中文的字符串才能正确的转换成其对应的宽字节字符,否则(在LC_ALL="C"时),汉字会被看成2个单字节的字符,然后再转换成宽字节的字符,这样转换的结果显然是错误的!
- 这就是ifstream打开含中文路径的文件失败的原因,因为"D:\\测试\\test.cpp"转换后得到错误的路径,所以找不到指定路径!
三、解决方法
- 最好的方法就是使用“使用 Unicode 字符集”,因为不但可以避免此类问题,而且也提升的程序执行效率(系统底层都是使用宽字节的 window 核心程序有说)
- 如果是历史项目不方便大改的话,可以有以下两种方法实现,展示代码如下:
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中文路径问题分析的更多相关文章
- 浅析GDAL库C#版本支持中文路径问题
GDAL库对于C#的支持问题还是蛮多的,对于中文路径的支持就是其中之一(另一个就是通过OGR库获取图形的坐标信息). 关于C#支持中文路径,看过我之前博客的应该都不陌生,如果使用的是我修改过的GDAL ...
- GDAL打开HDF格式时遇到的中文路径问题(未解决)
众所周知,中文环境下(VS2010 C++工程编码为多字节编码),在使用1.8.0版本以后的GDAL打开中文路径下的影像文件(如GeoTiff文件)时, 需对中文文件路径做特殊处理,有2种方法:(我使 ...
- QGis、Gdal本地中文路径问题
编译qgis完整项目后,由于Gdal库的原因,中文路径下通过添加矢量数据中数据库中是没有OGR的Oracle数据库功能的: 最开始打算通过重新编译gadl库从内部支持中文的(有成功的麻烦也请告诉我), ...
- CentOS个人目录下中文路径转英文路径
CentOS个人目录下中文路径转英文路径 如果安装了中文版到CentOS之后,root目录及home目录下会出现中文到路径名,如"桌面"."文档"," ...
- Atitit.url 汉字中文路径 404 resin4 resin 解决 v2 q329
Atitit.url 汉字中文路径 404 resin4 resin 解决 v2 q329 1. Pluginx机制1 2. Code1 3. 参考4 1. 原理 过滤器 ,,拦截jpg w ...
- 解决ckeditor中文路径无法下载,无法显示图片问题
使用ckfinder上传的文件如果是中文路径,下载的时候会找不到 假如使用tomcat服务器,找到tomcat目录>conf文件夹的server.xml>用查找找到Connector这个 ...
- 解决 git 中文路径显示 unicode 代码的问题
解决 git 中文路径显示 unicode 代码的问题 当被修改的文件中带有中文字符时,中文字符会被转换为 unicode 代码,看不出原来的文件名. 这时,只要配置 :: git config -- ...
- 关于 MAXScript 中文路径返回上级目录(精简版)
之前写过一个 关于 MAXScript 中文路径返回上级目录 的博文 今天无意中发现了一个更简单的方法 代码如下: fn newfile filepath = ( nf = getfilenamepa ...
- struts2中form提交到action中的中文参数乱码问题解决办法(包括取中文路径)
我的前台页是这样的: <body> <form action="test.action" method="post"> ...
随机推荐
- android图形基础知识
Android核心分析(23)-----Andoird GDI之基本原理及其总体框架 2010-06-13 22:49 18223人阅读 评论(18) 收藏 举报 AndroidGDI基本框架 在An ...
- Heroku使用
先要生成一个公钥,使用命令:$ ssh-keygen -t rsaGenerating public/private rsa key pair.Enter file in which to save ...
- centos 服务器装与python34源码安装
http://www.111cn.net/sys/CentOS/63645.htm 1.CentOS安装Python的依赖包(不安装依赖包,会导致python安装不完整) yum groupinsta ...
- window.open窗口居中和窗口最大化
1.window.open()参数 window.open(pageURL,name,parameters) 其中: pageURL为子窗口路径 name为子窗口句柄 parameters为窗口参数( ...
- C语言基础学习基本数据类型-其他整数类型
其他整数类型 初学C语言时,int类型会满足你对整数的大多数需求. C语言还提供了三个关键字用以修饰基本的整数类型:short.long和unsigned.有以下几个注意点: (1)C语言没有具体规定 ...
- Android网络框架比较
今天,公司需要为一个安卓app选择一个合适的网络框架,具体我了解,主要的安卓网络框架有okhttp,retrofit,android-async-http,volley. 查找网上的资料,大致可以得到 ...
- oracle 主键应用序列和触发器实现自动增长
oracle 主键自动增长 这几天搞Oracle,想让表的主键实现自动增长,查网络实现如下: create table simon_example ( id number(4) not null pr ...
- Android4.0强制横屏竖屏
Android的启动默认是横屏或者竖屏我们的TV本来是横屏显示,但是有客户竟然要竖屏显示,昨天快下班收到的需求,竟然说7.19就要搞定.思路有2个,一个就是修改LCD的默认输出,但是这个不是我这个水平 ...
- FastMM内存泄露
转自:http://www.2ccc.com/article.asp?articleid=4879FastMM是非常优秀的内存管理器,但是从FastMM4Options.inc中找到合适自已程序的选项 ...
- 利用php unpack读取c struct的二进制数据,struct内存对齐引起的一些问题
c语言代码 #include <stdio.h> struct test{ int a; unsigned char b; int c; }; int main(){ FILE *fp; ...