《碰到的一个编码问题》的回答:UTF-8的汉字字节!

本文探讨了UTF-8编码中一个汉字使用的字节数,并解释了使用byte[]和StringBuffer处理UTF-8编码文件时导致中文乱码的原因。文章提供了正确的处理方法和示例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

埋伏:
1、UTF-8用几个字节表示一个汉字?
这各答案你可能了解,但也可能不了解,我敢打保票一半人会不清楚(包括特意查资料之前的我)。
了解这个对编程有什么影响?


以下我把对yoolywu的回答,转为帖子发表,以表重视。


[b]yollywu的问:[/b][quote]系统有两个子系统,一个是BS的,一个是delphi做的CS,中间的数据传输是通过XML进行传输的。在XML传输的功能实现后,要求对XML进行加密解密.加密解密算法是CS端用delphi写的,然后这边用JAVA写个同样的算法。现在碰到的一个问题是:
用该算法的时候,CS和BS各自都能够加解密,我这边的过程是这样的。。。。[但最后]中文始终是乱码
[code]
StringBuffer strbuf = new StringBuffer();
try {
FileInputStream in = new FileInputStream(file);
int size = 0;
byte [] buf = new byte[1024];
while ((size=in.read(buf)) != -1) {
strbuf.append(new String(buf,0,size));
}

} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
return strbuf;
[/code]
[/quote]


[b]Qieqie的答:[/b]


以下的代码是错误的:
[code]
StringBuffer strbuf = new StringBuffer();
...
strbuf.append(new String(buf,0,size));
[/code]

第一、
你应该使用ByteArrayOutputStream,将InputStream的字节全部读出来,然后转成byte[]数组,最后在根据你和对方协议规定的字符集合(假设你们规定的是UTF-8,如果没有规定,那么就补充上吧),将byte[]变成String: String theString = new String(bytes, "UTF-8")。
不加"UTF-8"的new String,将使用Java环境设置的字符集,没有特别设置的情况下也就是操作系统的字符集。这是不可靠的。

第二、
[b]不能使用byte[]+StringBuffer[/b]:StringBuffer是针对char操作的(String也是)。读取byte时可能刚好把一个多字节的char分成前后两批加入StringBuffer。这样就破坏了char的完整性了。而如果你使用UTF-8编码的中文,你就会中招,导致乱码(其实是因为你的读取是由于byte失去原有顺序导致的,跟一般的乱码还不一样)
--
在UTF-8编码集中,每个汉字使用[size=18][color=red] [b]3[/b][/color][/size]个字符表示! 实践证明:
1、创建一个UTF-8编码的文件:weare.txt
2、写入三个字:“[b]我们是[/b]”
3、运行以下代码:
[code]
public class UTF8 {

public static void main(String[] args) throws IOException {
String p = "weare.txt";
InputStream in = new FileInputStream(p);
int read = in.read(new byte[1204]);
System.out.println(read);

}
}
[/code]
4、你会发现打印出来的是 [color=red]9[/color] !

所以,[b]byte[]+StringBuffer[/b]的使用方式是错误的!

不过可以使用StringBuffer + bufferedReader.readLine(),读出一行行后再加入StringBuffer。
或者第2楼说的stringbuffer+reader.read(char[])的形式(毕竟错误是由于byte[]导致的,而非StringBuffer) :wink:


参考资料:

[quote="zh.wikipedia.org"]
UTF-8 使用一至四个字节为每个字符编码。128 个 ASCII 字符(Unicode 范围由 U+0000 至 U+007F)只需一个字节,带有变音符号的拉丁文、希腊文、西里尔字母、亚美尼亚语、希伯来文、阿拉伯文、叙利亚文及马尔代夫语(Unicode 范围由 U+0080 至 U+07FF)需要二个字节,其他基本多文种平面(BMP)中的字符(CJK属于此类-Qieqie注)使用[b][color=red]三个字节[/color][/b],其他 Unicode 辅助平面的字符使用四字节编码。


[/quote]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值