河北卓正国际酒店:字符集处理
来源:百度文库 编辑:偶看新闻 时间:2024/04/29 09:11:22
1. 编码问题的由来,相关概念的理解
1.1 字符与编码的发展
从计算机对多国语言的支持角度看,大致可以分为三个阶段:
系统内码
说明
系统
阶段一
ASCII
计算机刚开始只支持英语,其它语言不能够在计算机上存储和显示。
英文 DOS
阶段二
ANSI编码
(本地化)
为使计算机支持更多语言,通常使用 0x80~0xFF 范围的 2 个字节来表示 1 个字符。比如:汉字 '中' 在中文操作系统中,使用 [0xD6,0xD0] 这两个字节存储。
不同的国家和地区制定了不同的标准,由此产生了 GB2312, BIG5, JIS 等各自的编码标准。这些使用 2 个字节来代表一个字符的各种汉字延伸编码方式,称为 ANSI 编码。在简体中文系统下,ANSI 编码代表 GB2312 编码,BIG5用于港台地区,繁体字,在日文操作系统下,ANSI 编码代表 JIS 编码。
不同 ANSI 编码之间互不兼容,当信息在国际间交流时,无法将属于两种语言的文字,存储在同一段 ANSI 编码的文本中。
中文 DOS,中文 Windows 95/98,日文 Windows 95/98
阶段三
UNICODE
(国际化)
为了使国际间信息交流更加方便,国际组织制定了 UNICODE 字符集,为各种语言中的每一个字符设定了统一并且唯一的数字编号,以满足跨语言、跨平台进行文本转换、处理的要求。
Windows NT/2000/XP,Linux,Java
字符串在内存中的存放方法:
在 ASCII 阶段,单字节字符串使用一个字节存放一个字符(SBCS)。比如,"Bob123"在内存中为:
42
6F
62
31
32
33
00
B
o
b
1
2
3
\0
在使用 ANSI 编码支持多种语言阶段,每个字符使用一个字节或多个字节来表示(MBCS),因此,这种方式存放的字符也被称作多字节字符。比如,"中文123"在中文 Windows 95 内存中为7个字节,每个汉字占2个字节,每个英文和数字字符占1个字节:
D6
D0
CE
C4
31
32
33
00
中
文
1
2
3
\0
在 UNICODE被采用之后,计算机存放字符串时,改为存放每个字符在 UNICODE 字符集中的序号。目前计算机一般使用 2 个字节(16 位)来存放一个序号(DBCS),因此,这种方式存放的字符也被称作宽字节字符。比如,字符串 "中文123"在 Windows 2000 下,内存中实际存放的是 5 个序号:
2D
4E
87
65
31
00
32
00
33
00
00
00
← 在 x86 CPU 中,低字节在前
中
文
1
2
3
\0
一共占 10 个字节。
1.2 字符,字节,字符串
理解编码的关键,是要把字符的概念和字节的概念理解准确。这两个概念容易混淆,我们在此做一下区分:
概念描述
举例
字符
人们使用的记号,抽象意义上的一个符号。
'1', '中', 'a', '$', '¥', ……
字节
计算机中存储数据的单元,一个8位的二进制数,是一个很具体的存储空间。
0x01, 0x45, 0xFA, ……
ANSI
字符串
在内存中,如果“字符”是以 ANSI 编码形式存在的,一个字符可能使用一个字节或多个字节来表示,那么我们称这种字符串为 ANSI 字符串或者多字节字符串。
"中文123"
(占7字节)
UNICODE
字符串
在内存中,如果“字符”是以在 UNICODE 中的序号存在的,那么我们称这种字符串为 UNICODE 字符串或者宽字节字符串。
L"中文123"
(占10字节)
由于不同 ANSI 编码所规定的标准是不相同的,因此,对于一个给定的多字节字符串,我们必须知道它采用的是哪一种编码规则,才能够知道它包含了哪些“字符”。而对于 UNICODE 字符串来说,不管在什么环境下,它所代表的“字符”内容总是不变的。
1.3 字符集与编码
各个国家和地区所制定的不同 ANSI 编码标准中,都只规定了各自语言所需的“字符”。比如:汉字标准(GB2312)中没有规定韩国语字符怎样存储。这些 ANSI 编码标准所规定的内容包含两层含义:
- 使用哪些字符。也就是说哪些汉字,字母和符号会被收入标准中。所包含“字符”的集合就叫做“字符集”。
- 规定每个“字符”分别用一个字节还是多个字节存储,用哪些字节来存储,这个规定就叫做“编码”。
各个国家和地区在制定编码标准的时候,“字符的集合”和“编码”一般都是同时制定的。因此,平常我们所说的“字符集”,比如:GB2312, GBK, JIS 等,除了有“字符的集合”这层含义外,同时也包含了“编码”的含义。
“UNICODE 字符集”包含了各种语言中使用到的所有“字符”。用来给 UNICODE 字符集编码的标准有很多种,比如:UTF-8, UTF-7, UTF-16, UnicodeLittle, UnicodeBig 等。
1.4 常用的编码简介
简单介绍一下常用的编码规则,为后边的章节做一个准备。在这里,我们根据编码规则的特点,把所有的编码分成三类:
分类
编码标准
说明
单字节字符编码
ISO-8859-1
最简单的编码规则,每一个字节直接作为一个 UNICODE 字符。比如,[0xD6, 0xD0] 这两个字节,通过 iso-8859-1 转化为字符串时,将直接得到 [0x00D6, 0x00D0] 两个 UNICODE 字符,即 "?D"。
反之,将 UNICODE 字符串通过 iso-8859-1 转化为字节串时,只能正常转化 0~255 范围的字符。
ANSI 编码
GB2312,
BIG5,
Shift_JIS,
ISO-8859-2 ……
把 UNICODE 字符串通过 ANSI 编码转化为“字节串”时,根据各自编码的规定,一个 UNICODE 字符可能转化成一个字节或多个字节。
反之,将字节串转化成字符串时,也可能多个字节转化成一个字符。比如,[0xD6, 0xD0] 这两个字节,通过 GB2312 转化为字符串时,将得到 [0x4E2D] 一个字符,即 '中' 字。
“ANSI 编码”的特点:
1. 这些“ANSI 编码标准”都只能处理各自语言范围之内的 UNICODE 字符。
2. “UNICODE 字符”与“转换出来的字节”之间的关系是人为规定的。
UNICODE 编码
UTF-8,
UTF-16, UnicodeBig ……
与“ANSI 编码”类似的,把字符串通过 UNICODE 编码转化成“字节串”时,一个 UNICODE 字符可能转化成一个字节或多个字节。
与“ANSI 编码”不同的是:
1. 这些“UNICODE 编码”能够处理所有的 UNICODE 字符。
2. “UNICODE 字符”与“转换出来的字节”之间是可以通过计算得到的。
我们实际上没有必要去深究每一种编码具体把某一个字符编码成了哪几个字节,我们只需要知道“编码”的概念就是把“字符”转化成“字节”就可以了。对于“UNICODE 编码”,由于它们是可以通过计算得到的,因此,在特殊的场合,我们可以去了解某一种“UNICODE 编码”是怎样的规则。
2. 字符与编码在程序中的实现
2.1 程序中的字符与字节
在 C++ 和 Java 中,用来代表“字符”和“字节”的数据类型,以及进行编码的方法:
类型或操作
C++
Java
字符
wchar_t
char
字节
char
byte
ANSI 字符串
char[]
byte[]
UNICODE 字符串
wchar_t[]
String
字节串→字符串
mbstowcs(), MultiByteToWideChar()
string = new String(bytes, "encoding")
字符串→字节串
wcstombs(), WideCharToMultiByte()
bytes = string.getBytes("encoding")
以上需要注意几点:
- Java 中的 char 代表一个“UNICODE 字符(宽字节字符)”,而 C++ 中的 char 代表一个字节。
- MultiByteToWideChar() 和 WideCharToMultiByte() 是 Windows API 函数。
3.ASCII,GB2313,GBK ,GB1803,UNICODE,UTF-8,UTF-16
ASCII:用7位不同的比特位组合表示不同的英文字母及符号
ASCII码只能表示英文字母,那中文怎么表示?
GB2313: 规定:一个小于127的字符的意义与原来相同,但两个大于127的字符连在一起时,就表示一个汉字,前面的一个字节(他称之为高字节)从0xA1用到 0xF7,后面一个字节(低字节)从0xA1到0xFE,这样我们就可以组合出大约7000多个简体汉字了。在这些编码里,我们还把数学符号、罗马希腊的字母、日文的假名们都编进去了,连在 ASCII 里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的"全角"字符,而原来在127号以下的那些就叫"半角"字符了。
中国人民看到这样很不错,于是就把这种汉字方案叫做 "GB2312"。GB2312 是对 ASCII 的中文扩展。
后来还是不够用,于是干脆不再要求低字节一定是127号之后的内码,只要第一个字节是大于127就固定表示这是一个汉字的开始,不管后面跟的是不是扩展字符集里的内容。结果扩展之后的编码方案被称为 GBK 标准,GBK 包括了 GB2312 的所有内容,同时又增加了近20000个新的汉字(包括繁体字)和符号。
后来少数民族也要用电脑了,于是再扩展,又加了几千个新的少数民族的字,GBK 扩成了GB18030。从此之后,中华民族的文化就可以在计算机时代中传承了。
中国的程序员们看到这一系列汉字编码的标准是好的,于是通称他们叫做 "DBCS"(Double Byte Charecter Set 双字节字符集)。在DBCS系列标准里,最大的特点是两字节长的汉字字符和一字节长的英文字符并存于同一套编码方案里,因此他们写的程序为了支持中文处理,必须要注意字串里的每一个字节的值,如果这个值是大于127的,那么就认为一个双字节字符集里的字符出现了。
因为当时各个国家都像中国这样搞出一套自己的编码标准,结果互相之间谁也不懂谁的编码,谁也不支持别人的编码,连大陆和台湾也分别采用了不同的 DBCS 编码方案——当时的中国人想让电脑显示汉字,就必须装上一个"汉字系统",专门用来处理汉字的显示、输入的问题,但是那个台湾地区用的电脑显示繁体字,得加装另一套支持 BIG5 编码才可以用,装错了字符系统,显示就会乱了套!这怎么办?除了中国,其他国家也需要显示他们的字符。
ISO(国际标谁化组织)的国际组织决定着手解决这个问题。他们采用的方法很简单:废了所有的地区性编码方案,重新搞一个包括了地球上所有文化、所有字母和符号的编码!这就是"Universal Multiple-Octet Coded Character Set",简称 UCS, 俗称"UNICODE"。
UNICODE 开始制订时,计算机的存储器容量极大地发展了,空间再也不成为问题了。于是 ISO 就直接规定必须用两个字节,也就是16位来统一表示所有的字符,对于ascii里的那些“半角”字符,UNICODE 包持其原编码不变,只是将其长度由原来的8位扩展为16位,而其他文化和语言的字符则全部重新统一编码。由于"半角"英文符号只需要用到低8位,所以其高 8位永远是0,因此这种大气的方案在保存英文文本时会多浪费一倍的空间。
从前多种字符集存在时,那些做多语言软件的公司遇上过很大麻烦,他们为了在不同的国家销售同一套软件,就不得不在区域化软件时也加持那个双字节字符集咒语,不仅要处处小心不要搞错,还要把软件中的文字在不同的字符集中转来转去。UNICODE 对于他们来说是一个很好的一揽子解决方案,于是从 Windows NT 开始,MS 趁机把它们的操作系统改了一遍,把所有的核心代码都改成了用 UNICODE 方式工作的版本,从这时开始,WINDOWS 系统终于无需要加装各种本土语言系统,就可以显示全世界上所有文化的字符了。
但是,UNICODE 在制订时没有考虑与任何一种现有的编码方案保持兼容,这使得 GBK 与UNICODE 在汉字的内码编排上完全是不一样的,没有一种简单的算术方法可以把文本内容从UNICODE编码和另一种编码进行转换,这种转换必须通过查表来进行。
如前所述,UNICODE 是用两个字节来表示为一个字符,他总共可以组合出65535不同的字符,这大概已经可以覆盖世界上所有文化的符号。如果还不够也没有关系,ISO已经准备了UCS-4方案,说简单了就是四个字节来表示一个字符,这样我们就可以组合出21亿个不同的字符出来(最高位有其他用途).
UNICODE 来到时,一起到来的还有计算机网络的兴起,UNICODE 如何在网络上传输也是一个必须考虑的问题,于是面向传输的众多 UTF(UCS TransferFormat)标准出现了,顾名思义,UTF8就是每次8个位传输数据,而UTF16就是每次16个位,只不过为了传输时的可靠性,从UNICODE到 UTF时并不是直接的对应,而是要过一些算法和规则来转换。
在网络里传递信息时有一个很重要的问题,就是对于数据高低位的解读方式,一些计算机是采用低位先发送的方法,例如我们PC机采用的 INTEL 架构,而另一些是采用高位先发送的方式,在网络中交换数据时,为了核对双方对于高低位的认识是否是一致的,采用了一种很简便的方法,就是在文本流的开始时向对方发送一个标志符——如果之后的文本是高位在位,那就发送"FEFF",反之,则发送"FFFE"。
big endian和little endian
big endian和little endian是CPU处理多字节数的不同方式。例如“汉”字的Unicode编码是6C49。那么写到文件里时,究竟是将6C写在前面,还是将49写在前面?如果将6C写在前面,就是big endian。如果将49写在前面,就是little endian。
讲到这里,我们再顺便说说一个很著名的奇怪现象:当你在 windows 的记事本里新建一个文件,输入"联通"两个字之后,保存,关闭,然后再次打开,你会发现这两个字已经消失了,代之的是几个乱码!
其实这是因为GB2312编码与UTF8编码产生了编码冲撞的原因。
从网上引来一段从UNICODE到UTF8的转换规则:
Unicode UTF-8
0000 - 007F 0xxxxxxx
0080 - 07FF 110xxxxx 10xxxxxx
0800 - FFFF 1110xxxx 10xxxxxx10xxxxxx
例如"汉"字的Unicode编码是6C49。6C49在0800-FFFF之间,所以要用3字节模板:1110xxxx10xxxxxx 10xxxxxx。将6C49写成二进制是:0110 1100 0100 1001,将这个比特流按三字节模板的分段方法分为0110 110001 001001,依次代替模板中的x,得到:1110-011010-110001 10-001001,即E6 B1 89,这就是其UTF8的编码。
而当你新建一个文本文件时,记事本的编码默认是ANSI,如果你在ANSI的编码输入汉字,那么他实际就是GB系列的编码方式,在这种编码下,"联通"的内码是:
c1 1100 0001
aa 1010 1010
cd 1100 1101
a8 1010 1000
注意到了吗?第一二个字节、第三四个字节的起始部分的都是"110"和"10",正好与UTF8规则里的两字节模板是一致的,于是再次打开记事本时,记事本就误认为这是一个UTF8编码的文件,让我们把第一个字节的110和第二个字节的10去掉,我们就得到了"00001 101010",再把各位对齐,补上前导的0,就得到了"00000000 0110 1010",不好意思,这是UNICODE的006A,也就是小写的字母"j",而之后的两字节用UTF8解码之后是0368,这个字符什么也不是。这就是只有"联通"两个字的文件没有办法在记事本里正常显示的原因。
而如果你在"联通"之后多输入几个字,其他的字的编码不见得又恰好是110和10开始的字节,这样再次打开时,记事本就不会坚持这是一个utf8编码的文件,而会用ANSI的方式解读之,这时乱码又不出现了。
4.程序中关于文件编码和字符转换的问题
4.1 查看各个文件的编码格式以及服务器传输的数据编码格式
用记事本打开文件,文件->另存为,下面的编码中显示的即为当前文件采用的编码格式。
或者用Ultraedit打开文件, UltraEdit 下方状态栏则真实的显示了当前打开文件的实际编码格式,而不是当前编辑的编码格式。 对于一个普通Ascii格式的文件,它显示为DOS 或者UNIX,对于一个包含有UTF-8编码字符的文件,它显示为U8-DOS 或者U8-UNIX,对于UTF-16编码的文件,它显示为U-DOS或者U-UNIX。
因此,如果通过UltraEdit打开文件查看BOM来确定文件格式,并不是安全的。BOM(Byte Order Mark),是UTF编码方案里用于标识编码的标准标记.如UNICODE的编码的文件 的BOM是 FF EF,UTF-8的BOM是EF BB BF , 但是一个UTF-8文件可能有BOM,也可能没有BOM。
服务器传输的数据编码格式查看,charset=utf-8 。
WindowsMobile 支持的UNICODE字符集,在Vodafone项目中,有时要显示西文和中文,所以必须转成UNICODE,
4.2 程序中的字符转换
程序中信息的交换多为 从文件或服务器中读取信息,经过一定的操作在UI上显示,而文件中的编码格式多为UTF-8或ANSI编码,是多字节显示一个字符,而UNICODE是宽字符,这就需要字符的转换,windows提供的接口WideCharToMultiByte 和MultiByteToWideChar。
1.hlp.cpp
WCHAR *GBK_to_Unicode(const char *_src)
{
int wlen = MultiByteToWideChar(CP_UTF8,0, _src, -1, 0, 0);
WCHAR * wstr =(WCHAR*) malloc((wlen + 1) * sizeof(WCHAR) );
if( MultiByteToWideChar(CP_UTF8, 0, _src,-1, wstr, wlen)==0)
{
free(wstr);
return NULL;
}
return wstr;
}
该函数名和函数体不符,本质上来说,该函数实现的功能和上面的UTF8_MutilByte_to_Unicode_Wide 是一致的,在创建manager面板的时候可以换一下。
GBK是ASCII码的扩展,加了中文字符字符集,个人认为它和UTF-8没有什么关系。
2.Operatewidget.cpp
bool UTF8ToGB(string &szOut,string& str)
{
WCHAR *strSrc;
CHAR * szRes;
int i = MultiByteToWideChar(CP_ACP,0, str.c_str(),-1, NULL, 0);
strSrc = new WCHAR[i+1];
MultiByteToWideChar(CP_ACP,0, str.c_str(),-1, strSrc, i);
i = WideCharToMultiByte(CP_ACP, 0, strSrc,-1, NULL, 0, NULL,NULL);
szRes = new CHAR[i+1];
WideCharToMultiByte(CP_ACP,0, strSrc, -1, szRes,i, NULL, NULL);
szOut = szRes;
delete []strSrc;
delete []szRes;
return true;
}
改为
bool UTF8ToGB(string &szOut,string& str)
{
WCHAR *strSrc =NULL;
CHAR * szRes = NULL;
int i = MultiByteToWideChar(CP_UTF8,0, str.c_str(),-1, NULL, 0);
strSrc = new WCHAR[i+1];
memset(strSrc,0,i+1);
MultiByteToWideChar(CP_UTF8,0, str.c_str(),-1, strSrc, i+1);
i = WideCharToMultiByte(GetACP(), 0, strSrc,-1, NULL, 0, NULL,NULL);
szRes = new CHAR[i+1];
memset(szRes,0,i+1);
WideCharToMultiByte(GetACP(),0, strSrc, -1, szRes,i+1, NULL,NULL);
szOut = szRes;
delete []strSrc;
delete []szRes;
return true;
}
因为UTF8ToGB 转换需要先将UTF8 转换为UNICODE ,然后再转换为GB,UTF8 转换为 UNICODE时需要用CP_UTF8代码页。
在控制台打印出业务名称,
printf("PanelManager::PM_CreatePanel,the name of widget%s",strHPName.c_str());
strHPName是从服务器发过来的数据中读取(UTF-8编码),而控制台 是ASCII(GB码),需要UTF8ToGB转换。
4.3字符集转换的实例
// unicode.cpp : Defines the entry point for the consoleapplication.
//
#include "stdafx.h"
#include "windows.h"
#include
#include
#include
#include
#include
using std::string;
using namespace std;
string WideToMutilByte_ANSI(const wchar_t * pwszSrc)
{
if (pwszSrc ==NULL || wcslen(pwszSrc)==0)
{
return "";
}
int nBufSize = WideCharToMultiByte(GetACP(),0, pwszSrc, -1, NULL,0, 0, FALSE);
char *pszBuf = new char[nBufSize];
nBufSize = WideCharToMultiByte(GetACP(), 0, pwszSrc,-1, pszBuf, nBufSize,0, FALSE);
string strRet(pszBuf);
delete []pszBuf;
pszBuf = NULL;
return strRet;
}
string WideToMutilByte_UTF8(const wchar_t * pwszSrc)
{
if (pwszSrc ==NULL || wcslen(pwszSrc)==0)
{
return "";
}
int nBufSize = WideCharToMultiByte(CP_UTF8,0, pwszSrc, -1, NULL,0, 0, FALSE);
char *pszBuf = new char[nBufSize];
nBufSize = WideCharToMultiByte(CP_UTF8, 0, pwszSrc,-1, pszBuf, nBufSize,0, FALSE);
string strRet(pszBuf);
delete []pszBuf;
pszBuf = NULL;
return strRet;
}
string UTF8_to_GB(const char * pstrSrc)
{
if(pstrSrc == NULL || strlen(pstrSrc) == 0)
{
return "";
}
WCHAR *strSrc =NULL;
CHAR * szRes = NULL;
int i = MultiByteToWideChar(CP_UTF8,0, pstrSrc, -1, NULL,0);
strSrc = new WCHAR[i+1];
memset(strSrc,0,i+1);
MultiByteToWideChar(CP_UTF8,0, pstrSrc, -1, strSrc,i+1);
i = WideCharToMultiByte(GetACP(), 0, strSrc,-1, NULL, 0, NULL,NULL);
szRes = new CHAR[i+1];
memset(szRes,0,i+1);
WideCharToMultiByte(GetACP(),0, strSrc, -1, szRes,i+1, NULL,NULL);
string strRes(szRes);
delete []strSrc;
delete []szRes;
return strRes;
}
wstring MutilByteToWide_ANSI(const char* pszSrc)
{
if (pszSrc == NULL || strlen(pszSrc)==0)
{
return L"";
}
int nBufSize = MultiByteToWideChar(GetACP(),0, pszSrc, -1, NULL,0);
wchar_t *pwszBuf =new wchar_t[nBufSize + 1];
nBufSize = MultiByteToWideChar(GetACP(), 0, pszSrc,-1, pwszBuf, nBufSize);
wstring wstrRet(pwszBuf);
delete []pwszBuf;
pwszBuf = NULL;
return wstrRet;
}
wstring MutilBytetoWide_UTF8(const char *_src)
{
if(_src == NULL || strlen(_src) == 0)
{
return L"";
}
int nBufSize = MultiByteToWideChar(CP_UTF8,0,_src,-1,NULL,0);
wchar_t *wsBuf = new wchar_t[nBufSize];
MultiByteToWideChar(CP_UTF8,0,_src,-1,wsBuf,nBufSize);
wstring wstrRet(wsBuf);
delete []wsBuf;
wsBuf = NULL;
return wstrRet;
}
int _tmain(int argc, _TCHAR* argv[])
{
wchar_t wText[20]= {L"宽字符转换实例!OK!"};
/*locale loc( "chs" );
wcout.imbue(loc);
wcout< cout<<"UNICODE: "< //默认下的字符集和代码页指向的是ANSI位置,正是这个原因,导致无法在console中输出含有中文的UNICODE字符串。所以我们只需要简单的设置下代码页即可 string strText1= ""; strText1 = WideToMutilByte_ANSI(wText); cout<<"UNICODEto ANSI: "< string strText2= ""; strText2 = WideToMutilByte_UTF8(wText); cout<<"UNICODEto UTF8: "< string strText3= ""; strText3 = UTF8_to_GB(strText2.c_str()); cout<<"UTF8_to_GB: "< cout< ofstream f1("d:\\me1.txt"); if(!f1) return 0; f1< f1.close(); ofstream f2("d:\\me2.txt"); if(!f2) return 0; f2< f2.close(); ifstream fin1; char Text1[50]; fin1.open("d:\\me1.txt"); fin1.getline(Text1, 50, '\n'); cout<<"ReadFrom ANSI file: "< ifstream fin2; char Text2[50]; fin2.open("d:\\me2.txt"); fin2.getline(Text2, 50, '\n'); cout<<"ReadFrom UTF8 file: "< string strText_fin= ""; strText_fin = UTF8_to_GB(Text2); cout<<"Aftertranslate: "< cout< /////////////////////////////////////////////////////////////////////////////////// wstring wstrText1= MutilByteToWide_ANSI(strText1.c_str()); //locale loc( "chs" ); // wcout.imbue(loc); //wcout< string strText4= ""; strText4 = WideToMutilByte_ANSI(wstrText1.c_str()); cout<<"ANSIto UNICODE to ANSI: "< string strText5= ""; strText5 = WideToMutilByte_UTF8(wstrText1.c_str()); cout<<"ANSIto UNICODE to UTF8: "< ofstream f4("d:\\me4.txt"); if(!f4) return 0; f4< f4.close(); ofstream f5("d:\\me5.txt"); if(!f5) return 0; f5< f5.close(); ///////////////////////////////////////////////////////////////////////////////////// wstring wstrText2= MutilBytetoWide_UTF8(strText2.c_str()); /*locale loc( "chs" ); wcout.imbue(loc); wcout< string strText6= ""; strText6 = WideToMutilByte_ANSI(wstrText2.c_str()); cout<<"UTF8 to UNICODE to ANSI: "< string strText7= ""; strText7 = WideToMutilByte_UTF8(wstrText2.c_str()); cout<<"UTF8to UNICODE to UTF8: "< ofstream f6("d:\\me6.txt"); if(!f6) return 0; f6<<"UTF8to UNICODE to ANSI: "< f6.close(); ofstream f7("d:\\me7.txt"); if(!f7) return 0; f7<<"UTF8to UNICODE to UTF8: "< f7.close(); getchar(); return 0; }