剖析ifstream打开含中文路径名文件失败的原因

http://blog.csdn.net/yukin_xue/article/details/7543423

最近写程序的时候遇到了使用ifstream打开含中文路径文件时失败的问题,在网上翻了一下,发现这是一个普遍遇到的问题,在很多人的博文中也都给出了一些解决技巧,但大多是转载的东西,很少对这个问题引发的原因有一个清晰、全面的解释。因此,我觉得有必要对该问题引发的原因作一个详细的剖析,希望对遇到同样问题的朋友们能有所帮助。

首先,用一个简单的例子来重现一下我所遇到的问题:

(1)在VS2008的“Property  Pages”属性页中,选择“Configuration Properties”-->“General”,可以看到当前使用的字符集是“Multi-Byte Character Set”,也就是说程序中使用的是多字节字符集。

(2)接下来看看ifstream打开txt文件的简单代码:

[cpp] view plaincopy

  1. #include "stdafx.h"
  2. #include <fstream>
  3. #include <iostream>
  4. using namespace std;
  5. int _tmain(int argc, _TCHAR* argv[])
  6. {
  7. ifstream infile("d://测试.txt");
  8. if(infile.is_open())
  9. {
  10. cout<<"Open Success!";
  11. }
  12. else
  13. {
  14. cout<<"Open Fail!";
  15. }
  16. return 0;
  17. }

(3)运行结果:输出“Open Fail”  (打开文件失败!)

从设置选项中可以看到,工程中使用的字符集可设置为“Multi-Byte Character Set”或“Unicode Character Set”,其中“Multi-Byte Character Set”表示使用ANSI编码方式,“Unicode Character Set”表示使用UNICODE编码方式。

那么这两种编码方式有什么样的区别呢?

(1)传统的计算机使用ANSI编码,在ANSI编码模式下,英文字符都用1个字节表示,而某些其它国家的文字(如汉字、日文),无法用单个字节来表示,ANSI便采用多个字节来表示这些字符(汉字是2个字节)。

(2)UNICODE包含UTF-8、UTF-16、UTF-32等多种编码方案(目前windows一般使用UTF-16)。拿UTF-16来说,规定所有字符都使用2个字节表示(不论英文字母还是汉字),对于超出2个字节范围的字符采用代理(采用4个字节表示)。

UNICODE相比ANSI有很多方面的优势(优势体现在哪?),微软非常提倡使用UNICODE编码方式,在MS较新版本的系统中都是采用UNICODE编码的。因此,即便我们在自己写的程序中使用了ANSI编码,系统会将其转换为UNICODE再对其进行处理。

接下来我们说一下ifstream。在调用ifstream的open方法时,系统内部调用mbstowcs_s进行文件名转换(mbstowcs_s函数的作用是把多字节字符转化为宽字符),需要注意的是,该函数的调用结果依赖于程序的本地化设置(什么是本地化设置?)。而本地化设置可以通过setlocale函数来设置,譬如:setlocale(LC_ALL, "chinese")表示将程序本身的语言设置为中文,而程序启动时默认设置为LC_ALL="C"。在使用mbstowcs_s进行字符串转换时,只有当LC_ALL="chinese"时,含中文的字符串才能正确的转换成其对应的宽字节字符,否则(在LC_ALL="C"时),汉字会被看成2个单字节的字符,然后再转换成宽字节的字符,这样转换的结果显然是错误的!这就是ifstream打开含中文路径的文件失败的原因,因为"d://测试.txt"转换后得到错误的路径,因此文件打不开!

解决方法如下:

   1: /********************************************************************
   2:     created:    2008/05/10
   3:     created:    10:5:2008   23:56
   4:     filename:     k:/sj/fstreamTest/fstreamTest/main.cpp
   5:     file path:    k:/sj/fstreamTest/fstreamTest
   6:     file base:    main
   7:     file ext:    cpp
   8:     author:        Gohan
   9: *********************************************************************/
  10: #include <tchar.h>
  11: #include <fstream>
  12: #include <iostream>
  13: using namespace std;
  14: int main()
  15: {
  16:     /************************************************************************/
  17:     /* 方法1,使用_TEXT()宏定义将字符串常量指定为TCHAR*类型                 */
  18:     /* 如果是我,首选此类型                                                 */
  19:     /************************************************************************/
  20:     fstream file;
  21:     file.open(_TEXT("c://测试//测试文本.txt"));
  22:     cout<<file.rdbuf();
  23:     file.close();
  24:  
  25:     /************************************************************************/
  26:     /* 方法2,使用STL中的locale类的静态方法指定全局locale                   */
  27:     /* 使用该方法以后,cout可能不能正常输出中文,十分蹊跷                    */
  28:     /* 我发现了勉强解决的方法:不要在还原区域设定前用cout或wcout 输出中文   */
  29:     /* 否则后果就是还原区域设定后无法使用cout wcout输出中文                 */
  30:     /************************************************************************/
  31:     locale::global(locale(""));//将全局区域设为操作系统默认区域
  32:     file.open("c://测试//测试文本2.txt");//可以顺利打开文件了
  33:     locale::global(locale("C"));//还原全局区域设定
  34:     cout<<file.rdbuf();
  35:     file.close();
  36:  
  37:     /************************************************************************/
  38:     /* 方法3,使用C函数setlocale,不能用cout输出中文的问题解决方法同上      */
  39:     /************************************************************************/
  40:     setlocale(LC_ALL,"Chinese-simplified");//设置中文环境
  41:     file.open("c://测试//测试文本3.txt");//可以顺利打开文件了
  42:     setlocale(LC_ALL,"C");//还原
  43:     cout<<file.rdbuf();
  44:     file.close();
  45: }

参见博客:http://www.cppblog.com/gohan/archive/2008/05/11/49488.html

由于windows提倡使用UNICODE编码,因此,我们在使用VS编写程序的时候,最好也都使用UNICODE字符集。这样有利于避免字符集转换带来的问题,同时,也有利于提高效率(前面提到,windows内部会把ANSI编码转换为UNICODE再处理,这些转换当然也带来了额外的时间消耗)。

在示例的程序中,可以将工程字符集设置为UNICODE,然后将字符串前面加上_T(这样,在字符集已经设置为UNICODE的情况下,该字符串会自动采用宽字符表示),例如:ifstream infile(_T("d://测试.txt")),便不会有打开文件不成功的问题了。

时间: 2024-07-30 18:15:12

剖析ifstream打开含中文路径名文件失败的原因的相关文章

windows下Python打开包含中文路径名文件

windows使用gbx(gb2312,gbk,gb18030我也不知道是哪个)对文件名及文件路径进行编码保存.打开文件的函数中使用诸如open(filename.encode('gbk'))可以很好的解决. #coding:utf8 if __name__ == '__main__': srcfile = r"D:/测试路径/测试文件.txt" f = open(srcfile.decode('utf8').encode('gbk')) for text in f.readlines

sublime text2 打开包含中文的文件会自动追加.dump后缀解决办法

用sublime text2 打开.c, .h,.txt等文件会自动追加一个.dump后缀,這样在打开.c,.h等文件时无法正常识别,从而无法正常进行语法着色,网上说是因为安装了GBK Encoding Support 插件的问题,于是就删除这个插件,发现再打开不会自动加.dump后缀了,但是遇到中文就乱码了, 因为GBK-.,这个插件就是解决中文乱码用的,那怎么办呢? 其实只要重新保存一下就可以了,比如我打开一个A.h文件,这个里有中文注释, 第一次打开时因为有中文所以sublime text

用adb pull命令从android系统中读取文件失败的原因及解决办法

问题:使用adb pull命令从android系统中读取文件失败.显示:Permission denied 原因:是由于文件权限原因引起. 使用ls -l命令查看android系统中的文件权限为: -rw-rw---- app_51   app_51 也就是说,该文件只有app_51用户以及app_51群组拥有读写权限,而adb shell的用户为shell,既不是app_51用户,也不在app_51群组中,所以没有权限读取这个文件.所以就出现了 Permission denied. 解决方法:

php ci框架中载入css和js文件失败的原因及解决方法

在将html页面整合到ci框架里面的时候,载入css和js失败. 原因是ci框架是入口的框架 对框架中文件的全部请求都须要经过index.php处理完毕,当载入外部的css和js文件的时候要使 用base_url()函数处理外部的链接. 在控制器中须要先加载url相关的类 public function test() { $this->load->helper('url'); $this->load->view('admin/test'); } 在test.php的view视图中.

php ci框架中加载css和js文件失败的原因及解决方法

在将html页面整合到ci框架里面的时候,加载css和js失败.原因是ci框架是入口的框架 对框架中文件的所有请求都需要经过index.php处理完成,当加载外部的css和js文件的时候要使 用base_url()函数处理外部的链接. 在控制器中需要先载入url相关的类 public function test() { $this->load->helper('url'); $this->load->view('admin/test'); } 在test.php的view视图中.

fopen打开文件失败的问题

fopen打开带中文路径或含中文名称的文件失败. 解决这个问题有两个方法:一是改用_wfopen,这个函数接受两个宽字符类型,函数原型如下: FILE* _wfopen(const wchar_t* filename, const wchar_t* mode); 参数一表示文件名,参数二表示打开模式,返回文件描述符 第二种方法还是用fopen,这种方式文件名称编码需要与系统保持一致. fopen是C标准库的一个函数,函数内部是系统调用.Windows中调用CreateFile:Linux中调用o

fopen打开文件失败原因分析

场景说明: 今天同事说,在已有的工具代码中,无法使用fopen打开文件,然后走过去进行协助.但是在解决问题的时候,已经先入为主的认为是:文件路径出现了字符转义的问题,根本没有想到要打印出当前无法获取到文件句柄的错误,是否是文件路径不存在.所以一开始就是将\替换为/,结果可想而知,没有任何的作用.然后替换为\\,还是不行.没有理由的,一直认为. 回去单独写最简单的测试程序,没有问题.怀疑是Unicode编码的问题,也排除了.这时候就开始百度fopen失败的原因获取.刚开始的时候准备使用GetLas

[python IO学习篇] [打开包含中文路径的文件]

https://my.oschina.net/mcyang000/blog/289460 打开路径含有中文的文件时,要注意: 1 在windows对文件名编码是采用gbk等进行编码保存,所以要将文件路径先解码,在按gbk编码: 字符串--解码成unicode--编码(注意str和unicode的转换) with open(r"D:\我的文档\桌面\python\config.ini".decode('utf8').encode('gbk'),'rb') as f: print f.re

windows中的txt文件上传到linux中,打开出现中文乱码

问题:在windows中显示正常的文件,上传到linux中,打开出现中文乱码. 解决方案:使用iconv命令 例如:iconv -f gbk -t utf8 shujujiegou.txt > shujujiegou.txt.utf8 原文地址:https://www.cnblogs.com/huangtao1927/p/8660815.html