《碰到的一个编码问题》的回答:UTF-8的汉字字节!
埋伏:
1、UTF-8用几个字节表示一个汉字?
这各答案你可能了解,但也可能不了解,我敢打保票一半人会不清楚(包括特意查资料之前的我)。
了解这个对编程有什么影响?
以下我把对yoolywu的回答,转为帖子发表,以表重视。
yollywu的问: 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 blocke.printStackTrace();} catch (IOException e1) {// TODO Auto-generated catch blocke1.printStackTrace();} return strbuf;
Qieqie的答:
以下的代码是错误的:
StringBuffer strbuf = new StringBuffer(); ... strbuf.append(new String(buf,0,size));
第一、
你应该使用ByteArrayOutputStream,将InputStream的字节全部读出来,然后转成byte[]数组,最后在根据你和对方协议规定的字符集合(假设你们规定的是UTF-8,如果没有规定,那么就补充上吧),将byte[]变成String: String theString = new String(bytes, "UTF-8")。
不加"UTF-8"的new String,将使用Java环境设置的字符集,没有特别设置的情况下也就是操作系统的字符集。这是不可靠的。
第二、
不能使用byte[]+StringBuffer:StringBuffer是针对char操作的(String也是)。读取byte时可能刚好把一个多字节的char分成前后两批加入StringBuffer。这样就破坏了char的完整性了。而如果你使用UTF-8编码的中文,你就会中招,导致乱码(其实是因为你的读取是由于byte失去原有顺序导致的,跟一般的乱码还不一样)
--
在UTF-8编码集中,每个汉字使用 3个字符表示! 实践证明:
1、创建一个UTF-8编码的文件:weare.txt
2、写入三个字:“我们是”
3、运行以下代码:
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);}}
4、你会发现打印出来的是 9 !
所以,byte[]+StringBuffer的使用方式是错误的!
不过可以使用StringBuffer + bufferedReader.readLine(),读出一行行后再加入StringBuffer。
或者第2楼说的stringbuffer+reader.read(char[])的形式(毕竟错误是由于byte[]导致的,而非StringBuffer)

参考资料:
InputStreamReader read=null; String line; try { read=new InputStreamReader (new FileInputStream(file),"UTF-8"); BufferedReader fileBuffer=new BufferedReader(read);line=fileBuffer.readLine(); while (line != null){ strbuf.append(line); strbuf.append("\n"); line = fileBuffer.readLine(); } } catch (IOException e4){ e4.printStackTrace(); },按字节读是另外有个经验的人说的,但是我发现两种读法都没能改变结果,所以就没有换过来,我觉的主要问题还真有可能是算法上面,就是说我在debug的时候解密后的串转码UTF-8后,因为始终都有几个汉字不能正常显示。 6 楼 yollywu 2007-08-18 谢谢各位,忙了我几天,一直不敢确定是哪边的错误,刚才被BOSS级人物解决了,他两边都懂,分析结果是那边算法有一处小问题造成的。 7 楼 hax 2007-08-18 我还以为utf8中中文是3个字节是基本常识呢,没想到还是有人不清楚。。。faint 8 楼 Qieqie 2007-08-18 LS的别ft,现实就是这样。
投入门贴的同学,认为这个知识简单,没有体认到“一个汉字用两个字节表示”的错误的结论几乎根深蒂固,因为根深蒂固,所以需要特别发帖指出。
(是否解决了yollywu的问题或者没解决可能不重要|因为也不是很了解他的问题。只是借yollywu的帖子作为引子而已,yollywu见谅) 9 楼 Qieqie 2007-08-18 yollywu 写道 想说的一个问题是,协议方过来的是加密后十六进制数的一个大的字符串。文件格式我打开的时候另存默认格式是ANSI.
绕了一圈。被你提醒这一说,问题就不是出在编码上。而是这样:
1、密文单位是字节而非字符,那用什么编码读取都可以,UTF-8/GBK/ISOxxxx都可以,他们是兼容ISOxxxx的
2、既然是字节而非字符,那byte[]+StringBuffer不是问题的错误所在,用它读没有问题(肯定是对方的问题,刚好你们的协调人帮你发现了问题确实如此)
3、但,把密文转为明文后,再读取要用预先指定的字符集读取(此时不能使用byte[]+StringBuffer) 10 楼 yollywu 2007-08-18 实际上跟知道不知道UTF-8是几个字节一点关系都没有,最后把加解密算法重新都改成了对字节的操作。
不过还是谢谢切切。 11 楼 bigpanda 2007-08-19 可以看看我这篇博客:Utf-8编码是如何工作的 http://bigpanda.iteye.com/blog/31890 12 楼 wangbing111 2007-08-19 引用
1、创建一个UTF-8编码的文件:weare.txt
2、写入三个字:“我们是”
3、运行以下代码:
代码
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);
}
}
4、你会发现打印出来的是 9 !
怎么我的文件是12个字节,打印结果是 12 ? 13 楼 hax 2007-08-19 楼上的,你保存的文件可能带有BOM。 14 楼 dogstar 2007-08-19 utf-8表示英文用一个字节表示一个,和Ascii一样。表示汉字就不一定了。
UTF-8用1到6个字节编码UNICODE字符。如果UNICODE字符由2个字节表示,则编码成UTF-8很可能需要3个字节,而如果UNICODE 字符由4个字节表示,则编码成UTF-8可能需要6个字节。用4个或6个字节去编码一个UNICODE字符可能太多了,但很少会遇到那样的UNICODE 字符。 15 楼 tvjody 2007-08-20 编码确实是个碍手的问题