Java中的字符编码与解码

本文深入探讨了Java程序中的字符编码、UTF-16与UTF-8编码原理及应用,以及GBK编码特性,同时提供了针对不同编码的文件存储实践,包括字节流与字符流的正确使用方法。

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

  1. import  java .io.BufferedReader;   
  2. import  java .io.FileInputStream;   
  3. import  java .io.FileNotFoundException;   
  4. import  java .io.FileOutputStream;   
  5. import  java .io.IOException;   
  6. import  java .io.InputStreamReader;   
  7. import  java .io.OutputStream;   
  8. import  java .io.OutputStreamWriter;   
  9. import  java .io.UnsupportedEncodingException;   
  10.   
  11. import  junit.framework.TestCase;   
  12.   
  13. /**   
  14. * 编码与解码测试   
  15. * @author jzj   
  16. */   
  17. public  class  TestEncodeDecode extends  TestCase {   
  18.     private  char  chineseChar = '中' ;   
  19.     private  char  englishChar = 'a' ;   
  20.   
  21.     /**   
  22.     * Java 程序中的字符都是占用二个字节,因为 char 类型好比双字节的无符号整数   
  23.     */   
  24.     public  void  testCharToUnicode() {   
  25.         //十进制Uncode编码    
  26.         System.out.println((int ) chineseChar);//20013    
  27.         System.out.println((int ) englishChar);//97    
  28.   
  29.         //十六进制Uncode编码    
  30.         System.out   
  31.                 .println(Integer.toHexString((int ) chineseChar).toUpperCase());//4E2D    
  32.         System.out   
  33.                 .println(Integer.toHexString((int ) englishChar).toUpperCase());//61    
  34.   
  35.         //二进制Uncode编码    
  36.         System.out.println(Integer.toBinaryString((int ) chineseChar));//100111000101101    
  37.         System.out.println(Integer.toBinaryString((int ) englishChar));//1100001    
  38.     }   
  39.   
  40.     /**   
  41.     * 不管是中文还是英文都还是其他字符,每个字符都是占用两个字节,英文字符的   
  42.     * UTF-16编码与Unicode编码是一样的,只不过UTF-16在编码时会在码流前加上"FE FF"两个字节的内容,   
  43.     * 表示字符是以UTF-16格式存储的,在读取时程序就会知道是UTF-16编码的字符   
  44.     */   
  45.     public  void  testCharToUTF16() {   
  46.         try  {   
  47.             //--中文字符转UTF-16    
  48.             byte [] encodeArr = String.valueOf(chineseChar).getBytes("UTF-16" );   
  49.             //十进制编码输出    
  50.             for  (int  i = 0 ; i < encodeArr.length; i++) {   
  51.                 //-2 -1 78 45    
  52.                 System.out.print(encodeArr[i] + " " );   
  53.             }   
  54.             System.out.println();   
  55.             //十六进制编码输出    
  56.             for  (int  i = 0 ; i < encodeArr.length; i++) {   
  57.                 //FE FF 4E 2D    
  58.                 System.out.print(byteToHex(encodeArr[i]) + " " );   
  59.             }   
  60.             System.out.println();   
  61.             //所占字节数    
  62.             System.out.println(encodeArr.length - 2 );//2    
  63.   
  64.             //--英文字符转UTF-16    
  65.             encodeArr = String.valueOf(englishChar).getBytes("UTF-16" );   
  66.             //十进制编码输出    
  67.             for  (int  i = 0 ; i < encodeArr.length; i++) {   
  68.                 //-2 -1 0 97    
  69.                 System.out.print(encodeArr[i] + " " );   
  70.             }   
  71.             System.out.println();   
  72.             //十六进制编码输出    
  73.             for  (int  i = 0 ; i < encodeArr.length; i++) {   
  74.                 //FE FF 00 61    
  75.                 System.out.print(byteToHex(encodeArr[i]) + " " );   
  76.             }   
  77.             System.out.println();   
  78.             //所占字节数    
  79.             System.out.println(encodeArr.length - 2 );//2    
  80.   
  81.         } catch  (UnsupportedEncodingException e) {   
  82.             e.printStackTrace();   
  83.         }   
  84.     }   
  85.   
  86.     /**  
  87.      * 以UTF-16写入文件时,也会把文件编码标志FE FF写入文件开头,但写入时不能编一码写一次文件,  
  88.      * 因为这样每次以UTF-16编码时,都会生成编码标志,且写文件时也写入了,这样只需第一次写文件  
  89.      * 时需要的标志却存入了多次,所以当以UTF-16存储字符时,最好一次性编码完成后再写入,或当字  
  90.      * 符太多时,我们用OutputStreamWriter进行包装后可以方便地进行多次写入,而不会多次写入文  
  91.      * 件编码标志,或者我们就用字节流来存,自已负责编码,但从第二次编码后写文件开始,手动去掉文  
  92.      * 件编码标志后再存入也是可以的,只不过没有像直接以字符流多次写入那样方便了。  
  93.      */   
  94.     public  void  testUTF16File() {   
  95.         try  {   
  96.             //--字节流多次写错误   
  97.             byte [] encodeArr = String.valueOf(chineseChar).getBytes("UTF-16" );   
  98.             OutputStream o = new  FileOutputStream("e:/utf16.txt" );   
  99.             o.write(encodeArr);   
  100.             encodeArr = String.valueOf(englishChar).getBytes("UTF-16" );   
  101.             o.write(encodeArr);   
  102.             o.close();   
  103.   
  104.             //--读   
  105.             BufferedReader br = new  BufferedReader(new  InputStreamReader(   
  106.                     new  FileInputStream("e:/utf16.txt" ), "UTF-16" ));   
  107.             //因为存储方法错误,所以导致读取时出现乱码,其实问号就是文件编码标志   
  108.             System.out.println(br.readLine());//中?a   
  109.             br.close();   
  110.   
  111.             //--正确字节流多次写   
  112.             encodeArr = String.valueOf(chineseChar).getBytes("UTF-16" );   
  113.             o = new  FileOutputStream("e:/utf16.txt" );   
  114.             o.write(encodeArr);   
  115.             encodeArr = String.valueOf(englishChar).getBytes("UTF-16" );   
  116.             //从第二次开始写入时,不要把文件编码多次写入文件,这样存储会正确   
  117.             o.write(encodeArr, 2 , encodeArr.length - 2 );//中a   
  118.             o.close();   
  119.   
  120.             //--读   
  121.             br = new  BufferedReader(new  InputStreamReader(new  FileInputStream(   
  122.                     "e:/utf16.txt" ), "UTF-16" ));   
  123.             System.out.println(br.readLine());//中a   
  124.             br.close();   
  125.   
  126.             //--正确的字符流写   
  127.             OutputStreamWriter ow = new  OutputStreamWriter(   
  128.                     new  FileOutputStream("e:/utf16.txt" ), "UTF-16" );   
  129.             ow.write(chineseChar);   
  130.             ow.write(englishChar);   
  131.             ow.close();   
  132.   
  133.             //--读   
  134.             br = new  BufferedReader(new  InputStreamReader(new  FileInputStream(   
  135.                     "e:/utf16.txt" ), "UTF-16" ));   
  136.             System.out.println(br.readLine());//中a   
  137.             br.close();   
  138.         } catch  (UnsupportedEncodingException e) {   
  139.   
  140.             e.printStackTrace();   
  141.         } catch  (FileNotFoundException e) {   
  142.             e.printStackTrace();   
  143.         } catch  (IOException e) {   
  144.             e.printStackTrace();   
  145.         }   
  146.     }   
  147.   
  148.     /**  
  149.      * 英文字符以UTF-8编码时只占一个字节或二字节(编码大于128小于256的英文字符),编码小于等于128的  
  150.      * 字符UTF-8字符与Unicode编码兼容,中文字符以UTF-8编码时,占三个字节。  
  151.      * 英文、中文使用的UTF-8编码规则模板分别是0xxxxxxx、1110xxxx 10xxxxxx 10xxxxxx  
  152.      * 如"中"字的Unicode编码是4E2D。4E2D在0800-FFFF之间,所以要用上面的三字节规则模板,  
  153.      * 将4E2D写成二进制是:0100 1110 0010 1101,将这个比特流按三字节模板的分段方法分为  
  154.      * 0100 111000 101101,依次代替模板中的x,得到:1110-0100 10-111000 10-101101,  
  155.      * 即 E4 B8 AD,这就是"中"字的UTF8的编码。  
  156.      */   
  157.     public  void  testCharToUTF8() {   
  158.         try  {   
  159.             //--中文字符转UTF-8   
  160.             byte [] encodeArr = String.valueOf(chineseChar).getBytes("UTF-8" );   
  161.             //十进制编码输出   
  162.             for  (int  i = 0 ; i < encodeArr.length; i++) {   
  163.                 //-28 -72 -83   
  164.                 System.out.print(encodeArr[i] + " " );   
  165.             }   
  166.             System.out.println();   
  167.             //十六进制编码输出   
  168.             for  (int  i = 0 ; i < encodeArr.length; i++) {   
  169.                 //E4 B8 AD   
  170.                 System.out.print(byteToHex(encodeArr[i]) + " " );   
  171.             }   
  172.             System.out.println();   
  173.             //所占字节数   
  174.             System.out.println(encodeArr.length);//3   
  175.             //--英文字符转UTF-8   
  176.             encodeArr = String.valueOf(englishChar).getBytes("UTF-8" );   
  177.             //十进制编码输出   
  178.             for  (int  i = 0 ; i < encodeArr.length; i++) {   
  179.                 //97   
  180.                 System.out.print(encodeArr[i] + " " );   
  181.             }   
  182.             System.out.println();   
  183.             //十六进制编码输出   
  184.             for  (int  i = 0 ; i < encodeArr.length; i++) {   
  185.                 //61   
  186.                 System.out.print(byteToHex(encodeArr[i]) + " " );   
  187.             }   
  188.             System.out.println();   
  189.             //所占字节数   
  190.             System.out.println(encodeArr.length);//1   
  191.   
  192.         } catch  (UnsupportedEncodingException e) {   
  193.             e.printStackTrace();   
  194.         }   
  195.     }   
  196.   
  197.     /**  
  198.      * 用Java 程序入文件中以UTF-8编码方式存入字符时,是不会在文件头加上编码标志的。  
  199.      * 但如果在windows中用记事本创建一个文件,并以UTF-8保存时,会在文件开开头写  
  200.      * 入文件编码标志 EF BB BF 三个字节长度的编码标志,这时如果使用字节流方式读取  
  201.      * 有编码标示的UTF-8文件时,会有问题,此时只能以字节流读出后去掉前三个字节内容  
  202.      */   
  203.     public  void  testUTF8File() {   
  204.         try  {   
  205.             //--字节流写   
  206.             byte [] encodeArr = String.valueOf(chineseChar).getBytes("UTF-8" );   
  207.             OutputStream o = new  FileOutputStream("e:/utf8.txt" );   
  208.             o.write(encodeArr);   
  209.             encodeArr = String.valueOf(englishChar).getBytes("UTF-8" );   
  210.             o.write(encodeArr);   
  211.             o.close();   
  212.   
  213.             //--读   
  214.             BufferedReader br = new  BufferedReader(new  InputStreamReader(   
  215.                     new  FileInputStream("e:/utf8.txt" ), "UTF-8" ));   
  216.             System.out.println(br.readLine());//中a   
  217.             br.close();   
  218.   
  219.             //--以字符流的方式读取windows记事本创建的有文件编码标志的UTF-8文件时错误   
  220.             br = new  BufferedReader(new  InputStreamReader(new  FileInputStream(   
  221.                     "e:/utf-8-2.txt" ), "UTF-8" ));   
  222.             System.out.println(br.readLine());//?中a   
  223.             br.close();   
  224.   
  225.             //--以字节流读取有编码标志的UTF-8文件   
  226.             FileInputStream fi = new  FileInputStream("e:/utf-8-2.txt" );   
  227.             byte [] b = new  byte [1024 ];   
  228.             int  readCount = fi.read(b);   
  229.             //手动丢弃前三个字节的内容   
  230.             System.out.println(new  String(b, 3 , readCount - 3"UTF-8" ));//中a   
  231.             fi.close();   
  232.         } catch  (UnsupportedEncodingException e) {   
  233.   
  234.             e.printStackTrace();   
  235.         } catch  (FileNotFoundException e) {   
  236.             e.printStackTrace();   
  237.         } catch  (IOException e) {   
  238.             e.printStackTrace();   
  239.         }   
  240.     }   
  241.   
  242.     /**  
  243.      * 英文字符以GBK编码时只占一个字节或二字节(编码大于128小于256的英文字符),编码小于等于128的  
  244.      * 字符GBK字符与Unicode编码兼容,中文字符以GBK编码时,占  
  245.      * 两个字节。  
  246.      * GBK对中文编码时,每个字节的最高位都是一  
  247.      */   
  248.     public  void  testCharToGBK() {   
  249.         try  {   
  250.             //--中文字符转GBK   
  251.             byte [] encodeArr = String.valueOf(chineseChar).getBytes("GBK" );   
  252.             //十进制编码输出   
  253.             for  (int  i = 0 ; i < encodeArr.length; i++) {   
  254.                 //-42 -48   
  255.                 System.out.print(encodeArr[i] + " " );   
  256.             }   
  257.             System.out.println();   
  258.             //十六进制编码输出   
  259.             for  (int  i = 0 ; i < encodeArr.length; i++) {   
  260.                 //D6 D0   
  261.                 System.out.print(byteToHex(encodeArr[i]) + " " );   
  262.             }   
  263.             System.out.println();   
  264.             //所占字节数   
  265.             System.out.println(encodeArr.length);//2   
  266.             //--英文字符转GBK   
  267.             encodeArr = String.valueOf(englishChar).getBytes("GBK" );   
  268.             //十进制编码输出   
  269.             for  (int  i = 0 ; i < encodeArr.length; i++) {   
  270.                 //97   
  271.                 System.out.print(encodeArr[i] + " " );   
  272.             }   
  273.             System.out.println();   
  274.             //十六进制编码输出   
  275.             for  (int  i = 0 ; i < encodeArr.length; i++) {   
  276.                 //61   
  277.                 System.out.print(byteToHex(encodeArr[i]) + " " );   
  278.             }   
  279.             System.out.println();   
  280.             //所占字节数   
  281.             System.out.println(encodeArr.length);//1   
  282.   
  283.         } catch  (UnsupportedEncodingException e) {   
  284.             e.printStackTrace();   
  285.         }   
  286.     }   
  287.   
  288.     public  void  testCharFromUTF16() {   
  289.         try  {   
  290.             byte [] encodeArr = String.valueOf(chineseChar).getBytes("UTF-16" );   
  291.             System.out.println(new  String(encodeArr, "UTF-16" ));//中   
  292.   
  293.             encodeArr = new  byte [] { -0x2 , -0x10x4E0x2D  };   
  294.             System.out.println(new  String(encodeArr, "UTF-16" ));//中   
  295.         } catch  (UnsupportedEncodingException e) {   
  296.             e.printStackTrace();   
  297.         }   
  298.     }   
  299.   
  300.     public  static  String byteToHex(byte  b) {   
  301.         return  Integer.toHexString((b & 0x000000FF ) | 0xFFFFFF00 ).substring(6 )   
  302.                 .toUpperCase();   
  303.     }   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值