zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    泛型的内部原理:类型擦除以及类型擦除带来的问题
    Redis的那些最常见面试问题
    线程池全面解析
    对线程调度中Thread.sleep(0)的深入理解
    集群环境下Redis分布式锁
    3.8
    3.7
    3.6任务
    3.5任务
    3.4
  • 原文地址:https://www.cnblogs.com/yht520/p/3589642.html
Copyright © 2011-2022 走看看