首页 > 其他分享 >CStdioFile在UNICODE字符集下读写中文

CStdioFile在UNICODE字符集下读写中文

时间:2022-12-07 17:33:24浏览次数:46  
标签:CStdioFile UNICODE stream 字符集 Unicode 字节


问题

  • 以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 编码的文件,

CStdioFile在UNICODE字符集下读写中文_多字节

网上也有个例子:

模仿着写了一份测试(测试确实可以这样用):

// 写入
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,stream,字符集,Unicode,字节
From: https://blog.51cto.com/u_15905375/5919847

相关文章

  • win32API 读写ANSI\UNICODE\UNICODE BIG-ENDIAN\UTF-8格式文本
    #include<windows.h>#include<tchar.h>#include<cassert>////读写文件的简单API函数封装//CFileBaseHelper//|......
  • 字符集和排序规则
    字符集我们可以为MySQL服务器、数据库、表、字符类型的字段以及字符串常量指定一个字符集(CharacterSet)和排序规则(Collation)。其中,字符集决定了能够存储哪些字符,比如AS......
  • 分享 ASCII 字符集的字模
    是做VGA显示屏时用到的,这是字模资源:gitee链接以下为字模代码://133*16*8字模的parameterparameter[7:0]C_ascii_character[2127:0]={0x00,0x00,0......
  • 网页返回unicode源码 python解码详细步骤
    刚入门python!记录一下网页返回源码,中文部分被unicode编码,python如何处理1.先提取编码后的数据(如果不提取正篇源码直接unicode解码,解码方法无法识别)这个步骤属于逻辑......
  • oracle19c 修改字符集
    环境:centos7.6oracle19c修改过程:shutdownimmediate;startupmount;ALTERSYSTEMENABLERESTRICTEDSESSION;ALTERSYSTEMSETJOB_QUEUE_PROCESSES=0;ALTE......
  • mysql字符集utf8和utf8mb4的使用问题
    一、MySQL中length()、char_length()的区别和用法char_length(str)计算单位:字符不管汉字还是数字或者是字母都算是一个字符length(str)计算单位:字节utf8编码:一个汉字三个字......
  • JS对Unicode编码和解码
    JavaScript编码和解码方法方法说明escape()使用转义序列替换某些字符来对字符串进行编码unescape()对使用escape()编码的字符串进行解码encodeURI()......
  • c++ utf8 unicode ansi 互转
    #include<codecvt>std::stringUnicodeToUTF8(conststd::wstring&wstr){std::stringret;try{std::wstring_convert<std::codecvt_utf8<wchar_t>>......
  • mysql 所有 表 字段 批量修改为utf8mb4字符集
    之前数据很多都是utf8不支持表情零零碎碎改了一部分总是有问题需要全部修改为utf8mb4相较原文章修改了一点点条件加了数据库和不为utf8mb4的筛选#改变字段数据SE......
  • mysql 修改字符集相关操作
    修改某个表字段的字符集ALTERTABLEapply_infoMODIFYmember_namevarchar(128)CHARACTERSETutf8mb4;查看某个库的字符集类型usechat;select@@character_set_dat......