Linux下UTF-8字符编码问题
-----------------------------------------这中间选自论坛我份发的帖子------------------------------------------------------------------地址是:http://topic.csdn.net/u/20101110/17/cab8cfc9-9ac6-47ce-98b4-e503e75e3e48.h
-----------------------------------------这中间选自论坛我份发的帖子------------------------------------------------------------------
地址是:http://topic.csdn.net/u/20101110/17/cab8cfc9-9ac6-47ce-98b4-e503e75e3e48.html?seed=1835214465&r=69782351#r_69782351---------------------------
各位达人,小弟有个问题请教各位,先谢了。
情况描述:
目的:写一个一个socket client端程序用于向socke server端发送信息(包括中英文),并接受回复和处理。
已完成:
1. 已完成英文的发送,并接受了server端发回的200 OK数据。 (比如函数如下:sendMyMSG(char *sendBuf,long sendLength))
2. 可以对回复信息进行处理。
3. 根据server端回复确认server接收utf-8编码的数据。
问题:
1. 如何向server端发送中文。
2. 我先查了下资料,发现有别人写好的编码转换的函数如下面的GB2312ToUTF8函数。
3. 而linux的默认编码是可以改变为utf-8的.(比如修改/etc/sysconfig/i18n)
4. 是不是我就可以在我的测试程序中将要发到函数sendMyMSG去的字符串之前调用下面的GB2312ToUTF8(或者类似的函数?×××ToUTF8.)我测试结果,还是不行。
我也查不到好的办法,不像Java可以直接将要发送的数据直接编码为utf-8,而不管你现在为何种编码。
附:
nt GB2312ToUTF8(char* srcStr, char* desBuff, size_t desBuffLength){
assert(strlen(srcStr)>0);
size_t iLen = strlen(srcStr);
iconv_t cd;
cd = iconv_open("utf-8","gb2312");
assert(cd != 0);
iconv(cd, &srcStr, &iLen, &desBuff, &desBuffLength);
iconv_close(cd); return desBuffLength;}-
---------------------------------------------分隔符----------------------------------------------------------------------------
最后解决办法和说明:
1. 因为linux本身默认是utf-8编码。
2. 所以不需要处理就可以将数据发往对方sockerserver了。
3. 只需要在编译的时候加上gcc -finput-charset=GB2312 myfile.c就可以了。
4. 原因在于如果你本身的函数中出现了中文gcc在编译的时候通过-finput-charset=GB2312参数就可以认出来了。
PS:
中间走了好多弯路,想附件中的GB2312ToUTF8函数。或者有人提出先将想发送的数据放至unicode编码的字符串然后在将unicode转变成utf8,最后再调用我的接口,事实证明就是绕了一个圈又回到了原地。
经验获取:
1. 了解了字符编码的相关知识。
2. 学习了如何将unicode和utf8的相互转变。
附录:
#include
#include
#include
#include
#include
wchar_t* ConvertUtf8ToUnicode(char* putf8)
{
int i,k,len;
assert(putf8);
len = strlen(putf8);
wchar_t* result = (wchar_t*)malloc(sizeof(wchar_t)*len);
if (result)
{ k = 0; for (i=0;i punicode[i])
{
result[k++] = (char)punicode[i];
}
else
{
result[k++] = (char)(0xe0|(punicode[i]>>12));
result[k++] = (char)(0x80|((punicode[i]>>6)&0x3f));
result[k++] = (char)(0x80|(punicode[i]&0x3f));
}
}
result[k++] = 0;
}
return result;
}
- char* ConvertUnicodeToUtf8(wchar_t* punicode)
- {
- int i,k,len;
- assert(punicode);
- len = wcslen(punicode);
- char* result = (char*)malloc(sizeof(char)*len*3);
- if (NULL != result)
- {
- k = 0;
- for (i=0;i<len;i++)
- {
- if (0x80 > punicode[i])
- {
- result[k++] = (char)punicode[i];
- }
- else
- {
- result[k++] = (char)(0xe0|(punicode[i]>>12));
- result[k++] = (char)(0x80|((punicode[i]>>6)&0x3f));
- result[k++] = (char)(0x80|(punicode[i]&0x3f));
- }
- }
- result[k++] = 0;
- }
- return result;
- }
========================================================
我们可以做个试验,使用记事本将“中国 ab”这个中英混杂的字符串以不同编码方式保存为多个“ .txt”文件,然后直接查看其二进制内容:
图1 比对字符编码
图 1 展示了“中国 ab”按四种编码方式( ANSI、 UTF8、 Unicode、 Unicode Big Endian )得到的不同二进制数据。
以英文字符“ a”为例, ANSI和 UTF8得到的数值都是“ 61”,但 Unicode将它扩充为 2个字节 16位的二进制(“ 61 00”和“ 00 61”),所以我们又将这种编码方式称为 UTF-16。
UTF-16 又可以细分为 2种编码方式: Big Endian方式与 Little_Edian方式,这两者的唯一区别在于字节排列顺序刚好相反, Little_Edian方式将“ a”编码为“ 61 00”,而 Big Endian方式则编码为“ 00 61”。
现在看看中文字符,“中国”两个汉字, ANSI编码为“ D6 D0 B9 FA”, 4个字节,一个汉字占两个字节,而 UTF8则编码为“ E4 B8 AD E5 9B BD”, 6个字节,一个汉字占 3个字节!这说明 UTF8是一种“变长”的编码,可能使用 1~4个字节来表示某个字符。
另外,我们看到 UTF8和 Unicode编码(不管是 Big Endian还是 Little Endian )前面都有几个标记字符,这些字符放在文本文件的开头,称为“ BOM( Byte Order Mark,字节顺序标记)”指明了文本的编码方式,以下是 .NET程序中常见的字符编码方式的 BOM值:
编码 | BOM 值 |
UTF-8 | EF BB BF |
UTF-16 big endian | FE FF |
UTF-16 little endian | FF FE |
UTF-32 big endian | 00 00 FE FF |
UTF-32 little endian | FF FE 00 00 |
了解了上述基础知识,我们就可以依据 BOM值自动检测字符串的编码方式,从而正确从二进制数据流中解码,以下代码检测文本二进制数据是否采用 UTF8编码:
byte [] FileContents = File.ReadAllBytes(FilePath);
int filelength = FileContents.Length;
// 检测BOM
if (FileContents[ 0 ] == 0xef && FileContents[ 1 ] == 0xbb && FileContents[ 2 ] == 0xbf )
{
// 按UTF8解码字符串,注意要排除掉BOM占用的3个字节。
String content = Encoding.UTF8.GetString( FileContents, 3 , filelength - 3 );
Console.WriteLine(content);
}
其他的编码方式都可以“依样画葫芦”。
更多推荐
所有评论(0)