java和unicode

故事是这样的,那天和同事讨论上传txt文件,如何能防止文件乱码,其间引出了如下问题:
[list]
[*]1.如何防止上传文件乱码(无论任何语言).
[*]2.用byte array&utf-8构造string,java如何判断几个byte一个中文字符.
[*]3.utf-8和unicode的区别.
[*]4.一个utf-8 string有几个char,几个byte?
[/list]
随着这些问题的解决,对java和unicode,utf-8之间的关系有了更深层的认识.


[b]如何防止上传文件乱码(无论任何语言).[/b]
为了支持i18n,我们必须要求上传文件的编码是utf-8或unicode,否则无法实现全语言的支持.utf-8的文件开头会有EF BB BF标志。

[b]用byte array&utf-8构造string,java如何判断几个byte一个中文字符.[/b]
因utf-8是变长编码,所以有些字符会是一个字节(如:ascii),有些会是3个(如:中文),
但在用byte array构造string时,jvm是如何判断以几个字节为一组来构造呢?
原来utf-8编码本身有标志可以判断,每个字符的第一个byte前几位是标示位10*,110*,1110*,11110*,其中1的个数代表这个字符有几个字节。

[b]utf-8和unicode的区别.[/b]
unicode是定长编码,每个字符都是2 byte,所以在存储ascii时会浪费一个byte的空间。而utf-8是变长unicode编码,在unicode编码基础上进行变长,在存储ascii时只占用一个byte.存储中文时占用3 byte.

[b]一个utf-8 string有几个char,几个byte?[/b]

String s = "中国";
byte[] b = s.getBytes("utf-8");
String s_utf8 = new String(b,"utf-8");
System.out.println(s_utf8.getBytes("utf-8").length);
System.out.println(s_utf8.toCharArray().length);

结果是:
6
2
按照上面的结果看好像一个char是3 byte,但java中一个char是2 byte,为什么?
其实java中无论什么字符集string都会以unicode编码来存储,所以每个char都是一个
unicode编码占两个byte。


import java.io.UnsupportedEncodingException;


public class TestUtf8File {

/**
* @param args
* @throws UnsupportedEncodingException
*/
public static void main(String[] args) throws UnsupportedEncodingException {

String s = "中国人";
byte[] b = s.getBytes("utf-8");
String s_utf8 = new String(b,"utf-8");
System.out.println(s_utf8.getBytes("utf-8").length);
System.out.println("utf-8 bytes:");
printByteArray(s_utf8.getBytes("utf-8"));
System.out.println("chars:");
printCharArray(s_utf8.toCharArray());

byte[] unicodeb= s.getBytes("unicode");
String s_unidode = new String(unicodeb,"unicode");
System.out.println("unicode bytes:");
printByteArray(s_unidode.getBytes("unicode"));

}

private static void printByteArray(byte[] b){
for(int i = 0;i < b.length; i++){
System.out.println((Integer.toString(b[i],16)));

}
}

private static void printCharArray(char[] c){
for(int i = 0;i < c.length; i++){
System.out.println(Integer.toString((byte)(c[i]>>8),16));
System.out.println(Integer.toString((byte)(c[i]&0xff),16));

}
}

}


output:
9
utf-8 bytes:
-1c
-48
-53
-1b
-65
-43
-1c
-46
-46
chars:
4e
2d
56
-3
4e
-46
unicode bytes:
-2
-1
4e
2d
56
-3
4e
-46


-2 -1(FE FF)是unicode big endian标志
fe ff:big endian
ff fe: no big endian
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章