CStdioFile在UNICODE字符集下读写中文
来源:互联网 发布:sql 外键必须是主键吗 编辑:程序博客网 时间:2024/05/18 00:31
问题
- 以CFile::typeBinary的形式读写包含中文的文件,未出现乱码。
- 以CFile::typeText方式读写, 分两种情况:在多字节字符集下,使用CStdioFile::ReadString读取包含中文的文件,正常;工程编码切换至UNICODE字符集,则出现了中文乱码。
探究
查找MSDN文档,获得以下信息:
Unicode™ Stream I/O in Text and Binary Modes
When a Unicode stream I/O routine (such as fwprintf, fwscanf, fgetwc, fputwc, fgetws, or
fputws) operates on a file that is open in text mode (the default),
two kinds of character conversions take place:
Unicode-to-MBCS or MBCS-to-Unicode conversion. When a Unicode stream-I/O function operates in text mode, the source or destination
stream is assumed to be a sequence of multibyte characters.
Therefore, the Unicode stream-input functions convert multibyte
characters to wide characters (as if by a call to the mbtowc
function). For the same reason, the Unicode stream-output functions
convert wide characters to multibyte characters (as if by a call to
the wctomb function).Carriage return – linefeed (CR-LF) translation. This translation occurs before the MBCS – Unicode conversion (for Unicode stream input
functions) and after the Unicode – MBCS conversion (for Unicode
stream output functions). During input, each carriage return –
linefeed combination is translated into a single linefeed character.
During output, each linefeed character is translated into a carriage
return – linefeed combination.However, when a Unicode stream-I/O function operates in binary mode,
the file is assumed to be Unicode, and no CR-LF translation or
character conversion occurs during input or output.
从以上信息中提取到关键信息:
在文本模式下,使用UNICODE版本的IO操作函数(如_wfopen,
fgetws等)时,函数会假定操作的对象是多字节序列(即文件存放的是多字节内容)。这些函数内部会做转换,比如读取时,就会将多字节序列转换成宽字节;写入时,就会将宽字节转换成多字节序列。在二进制模式下,函数会假定操作的对象是UNICODE序列(即文件存放的是UNICODE内容,即每个字符都用二或四(极少的情况下)个字节存储在文件中,除非显式写入,否则文件中不带BOM头)
网上搜集到的信息:
使用setlocale设置区域,原因(具体参看原文):
因为在C/C++语言标准中定义了其运行时的字符集环境为”C”,也就是ASCII字符集的一个子集,那么mbstowcs在工作时会将cstr中所包含的字符串看作是ASCII编码的字符,而不认为是一个包含有chs编码的字符串,所以他会将每一个中文拆成2个ASCII编码进行转换,这样得到的结果就是会形成4个wchar_t的字符组成的串,那么如何才能够让mbstowcs正常工作呢?在调用mbstowcs进行转换之间必须明确的告诉mbstowcs目前cstr串中包含的是chs编码的字符串,通过setlocale(
LC_ALL, “chs” )函数调用来完成,需要注意的是这个函数会改变整个应用程序的字符集编码方式,必须要通过重新调用setlocale(
LC_ALL, “C”
)函数来还原,这样就可以保证mbstowcs在转换时将cstr中的串看作是中文串,并且转换成为2个wchar_t字符,而不是4个。
代码举例:
//区域设定 char* old_locale = _strdup( setlocale(LC_CTYPE,NULL) ); setlocale( LC_CTYPE, "chs" ); //写入中文字串 CStdioFile mFile; if( mFile.Open( _T("test_file.txt"), CFile::modeCreate | CFile::modeReadWrite | CFile::typeText)) { try { mFile.WriteString( _T("在多字节字符集下,使用CStdioFile::ReadString") _T("读取包含中文的文件,正常。但是将工程编码切换至" _T("UNICODE字符集,则出现了中文乱码的情况。")) ); } catch (CException* e) { e->ReportError(); } mFile.Close(); } //读出字段 CStdioFile mFileRead; if ( mFileRead.Open( _T("test_file.txt"), CFile::modeRead | CFile::typeText ) ) { CString strTemp; mFileRead.ReadString( strTemp ); m_ctlDisplay.SetWindowText( strTemp ); } setlocale( LC_CTYPE, old_locale ); free( old_locale );//还原区域设定
引申
使用CStdioFile读取UTF8、UNICODE(UTF16)、UTF-16LE 编码的文件:
需要用到另一个构造函数CStdioFile( FILE* pOpenStream ),传给其一个FILE对象指针,其中FILE对象是通过_tfopen_s来得到的,_tfopen_s这个函数支持打开
UTF8、UNICODE(UTF16)、UTF-16LE 编码的文件,
网上也有个例子:例子
模仿着写了一份测试(测试确实可以这样用):
// 写入 FILE *fStream = NULL; errno_t e = _tfopen_s(&fStream, _T("text_file_utf8.txt"), _T("wt,ccs=UTF-8")); // or ccs=UTF-8 if (e != 0) return -1; // failed..CString sRead; CStdioFile mFile( fStream ); try { mFile.WriteString(_T("aaaa中文文本测试11")); } catch (CException* e) { e->ReportError(); } mFile.Close(); //读取 fStream = NULL; e = _tfopen_s(&fStream, _T("text_file_utf8.txt"), _T("rt,ccs=UTF-8")); // or ccs=UTF-8 if (e != 0) return -1; // failed..CString sRead; CStdioFile mFileRead( fStream ); try { CString strTemp; mFileRead.ReadString( strTemp ); m_ctlDisplay.SetWindowText( strTemp ); } catch (CException* e) { e->ReportError(); } mFileRead.Close();
- CStdioFile在UNICODE字符集下读写中文
- 解决UNICODE字符集下CStdioFile的Writestring无法写入中文的问题
- 解决UNICODE字符集下CStdioFile的Writestring无法写入中文的问题
- 解决UNICODE字符集下CStdioFile的Writestring无法写入中文的问题
- 解决UNICODE字符集下CStdioFile的Writestring无法写入中文的问题
- 解决UNICODE字符集下CStdioFile的Writestring无法写入中文的问题
- 解决UNICODE字符集下CStdioFile的Writestring无法写入中文的问题
- 解决UNICODE字符集下CStdioFile的Writestring无法写入中文的问题//setlocale
- 解决UNICODE字符集下CStdioFile的Writestring无法写入中文的问题
- 解决UNICODE字符集下CStdioFile的Writestring无法写入中文的问题
- CStdioFile在UNICODE环境下读取汉字
- VS2013在Unicode字符集下读写ANSI编码文件
- 解决UNICODE字符集下CStdioFile的Writestring无法写入中文的问题和在在原文件后写入文件
- 使用CStdioFile 读写UNICODE文档
- 使用CStdioFile 读写UNICODE文档
- 使用CStdioFile 读写UNICODE文档
- 通过CStdioFile读写unicode字符串
- vc2005 unicode下 cstdiofile无法写入中文的问题
- Guava学习笔记【7】:Guava新增集合类型-Multiset
- AndroidStudio&&Eclipse配置SVN
- BZOJ 1478 Sgu282 Isomorphism
- 简单的js onChange()
- Guava学习笔记【8】:Guava新增集合类型-Multimap
- CStdioFile在UNICODE字符集下读写中文
- java Element类的用法
- Guava学习笔记【9】:Guava新增集合类型-Bimap
- $('div','li') 和 $('div , li') 和 $('div li') 区别
- Leetcode学习(31)—— Add Digits
- Guava学习笔记【10】:Guava新集合-Table等
- 本CSDN博主将与北京航天航空大学出版社合作出版<嵌入式C语言技术实战开发>一书
- 吝啬的国度(dfs)
- MCM(平均曲率演化)