java和unicode

故事是这样的,那天和同事讨论上传txt文件,如何能防止文件乱码,其间引出了如下问题: 

     
  • 1.如何防止上传文件乱码(无论任何语言). 
  • 2.用byte array&utf-8构造string,java如何判断几个byte一个中文字符. 
  • 3.utf-8和unicode的区别. 
  • 4.一个utf-8 string有几个char,几个byte?

  随着这些问题的解决,对java和unicode,utf-8之间的关系有了更深层的认识. 


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

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

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

一个utf-8 string有几个char,几个byte? 
Java代码  收藏代码
  1. String s = "中国";     
  2. byte[] b = s.getBytes("utf-8");  
  3. String s_utf8 = new String(b,"utf-8");  
  4. System.out.println(s_utf8.getBytes("utf-8").length);  
  5. System.out.println(s_utf8.toCharArray().length);  

结果是: 
    6 
    2 
按照上面的结果看好像一个char是3 byte,但java中一个char是2 byte,为什么? 
其实java中无论什么字符集string都会以unicode编码来存储,所以每个char都是一个 
unicode编码占两个byte。 
Java代码  收藏代码
  1. import java.io.UnsupportedEncodingException;  
  2.   
  3.   
  4. public class TestUtf8File {  
  5.   
  6.   /** 
  7.    * @param args 
  8.    * @throws UnsupportedEncodingException  
  9.    */  
  10.   public static void main(String[] args) throws UnsupportedEncodingException {  
  11.   
  12.     String s = "中国人";     
  13.     byte[] b = s.getBytes("utf-8");  
  14.     String s_utf8 = new String(b,"utf-8");  
  15.     System.out.println(s_utf8.getBytes("utf-8").length);  
  16.     System.out.println("utf-8 bytes:");  
  17.     printByteArray(s_utf8.getBytes("utf-8"));  
  18.     System.out.println("chars:");  
  19.     printCharArray(s_utf8.toCharArray());  
  20.       
  21.     byte[] unicodeb= s.getBytes("unicode");  
  22.     String s_unidode = new String(unicodeb,"unicode");  
  23.     System.out.println("unicode bytes:");  
  24.     printByteArray(s_unidode.getBytes("unicode"));  
  25.   
  26.   }  
  27.     
  28.   private static void printByteArray(byte[] b){  
  29.     for(int i = 0;i < b.length; i++){  
  30.       System.out.println((Integer.toString(b[i],16)));  
  31.         
  32.     }  
  33.   }  
  34.     
  35.   private static void printCharArray(char[] c){  
  36.     for(int i = 0;i < c.length; i++){  
  37.       System.out.println(Integer.toString((byte)(c[i]>>8),16));  
  38.       System.out.println(Integer.toString((byte)(c[i]&0xff),16));  
  39.         
  40.     }  
  41.   }  
  42.   
  43. }  

output: 

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
posted @ 2013-02-27 11:43  可可ing  阅读(482)  评论(0编辑  收藏  举报