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"> ...
随机推荐
- 浅谈JS中的闭包
浅谈JS中的闭包 在介绍闭包之前,我先介绍点JS的基础知识,下面的基础知识会充分的帮助你理解闭包.那么接下来先看下变量的作用域. 变量的作用域 变量共有两种,一种为全局变量,一种为局部变量.那么全局变 ...
- 什么叫CallBack函数,怎么用回调函数?
JQuery众多常用方法中很经常会用到回调函数, 理解好js callback函数定义及用法,我们就可以利用callback函数帮我们做很多事情啦! A callback is a function ...
- C语言基础学习基本数据类型-变量的输出与输入
变量的输出 变量如何输入输出呢?实际上,在这之前你已经使用过输出语句(printf语句)了,我们可以使用printf来执行输出. printf语句的使用方法如下: printf(格式控制字符串, 数据 ...
- Swift数据类型之整型和浮点型-备
Swift提供8.16.32.64位形式的有符号及无符号整数.这些整数类型遵循C语言的命名规约,我归纳了Swift中的整型: 整型示例: print("UInt8 range: \(UInt ...
- rtf表格的合并
{\rtf1\ansi\ansicpg1252\deff0\deflang1033{\fonttbl{\f0\fnil Calibri;}{\f1\fnil\fcharset134 \'cb\'ce\ ...
- 《iPhone高级编程—使用Mono Touch和.NET/C#》
第1章 C#开发人员基于MonoTouch进行iPhone开发概述 1 1.1 产品对比 2 1.1.1 .NET Framework 2 1.1.2 Mono 2 1.1.3 MonoTouch 3 ...
- ELK 下载地址elastic
lasticsearch 2.3.5 Elasticsearch can also be installed from our repositories using apt or yum. See R ...
- 【No system images installed for this target】的解决方式
打开eclipse,新建安卓SDK模拟器时,选择完Target之后,再选择CPU/ABI时,默认为No system images installed for this target. 且无法编辑: ...
- cf442C Artem and Array
C. Artem and Array time limit per test 2 seconds memory limit per test 256 megabytes input standard ...
- php字符串常用处理函数(数组的拆分、查找替换)
//字符串常用函数 $a = "hello"; echo strlen($a); //输出字符串的长度 $b = "Hello"; ...