Java中的字符编码与解码

import java.io.BufferedReader;   
import java.io.FileInputStream;   
import java.io.FileNotFoundException;   
import java.io.FileOutputStream;   
import java.io.IOException;   
import java.io.InputStreamReader;   
import java.io.OutputStream;   
import java.io.OutputStreamWriter;   
import java.io.UnsupportedEncodingException;   
  
import junit.framework.TestCase;   
  
/**   
* 编码与解码测试   
* @author jzj   
*/  
public class TestEncodeDecode extends TestCase {   
    private char chineseChar = '中';   
    private char englishChar = 'a';   
  
    /**   
    * Java程序中的字符都是占用二个字节,因为 char 类型好比双字节的无符号整数   
    */  
    public void testCharToUnicode() {   
        //十进制Uncode编码    
        System.out.println((int) chineseChar);//20013    
        System.out.println((int) englishChar);//97    
  
        //十六进制Uncode编码    
        System.out   
                .println(Integer.toHexString((int) chineseChar).toUpperCase());//4E2D    
        System.out   
                .println(Integer.toHexString((int) englishChar).toUpperCase());//61    
  
        //二进制Uncode编码    
        System.out.println(Integer.toBinaryString((int) chineseChar));//100111000101101    
        System.out.println(Integer.toBinaryString((int) englishChar));//1100001    
    }   
  
    /**   
    * 不管是中文还是英文都还是其他字符,每个字符都是占用两个字节,英文字符的   
    * UTF-16编码与Unicode编码是一样的,只不过UTF-16在编码时会在码流前加上"FE FF"两个字节的内容,   
    * 表示字符是以UTF-16格式存储的,在读取时程序就会知道是UTF-16编码的字符   
    */  
    public void testCharToUTF16() {   
        try {   
            //--中文字符转UTF-16    
            byte[] encodeArr = String.valueOf(chineseChar).getBytes("UTF-16");   
            //十进制编码输出    
            for (int i = 0; i < encodeArr.length; i++) {   
                //-2 -1 78 45    
                System.out.print(encodeArr[i] + " ");   
            }   
            System.out.println();   
            //十六进制编码输出    
            for (int i = 0; i < encodeArr.length; i++) {   
                //FE FF 4E 2D    
                System.out.print(byteToHex(encodeArr[i]) + " ");   
            }   
            System.out.println();   
            //所占字节数    
            System.out.println(encodeArr.length - 2);//2    
  
            //--英文字符转UTF-16    
            encodeArr = String.valueOf(englishChar).getBytes("UTF-16");   
            //十进制编码输出    
            for (int i = 0; i < encodeArr.length; i++) {   
                //-2 -1 0 97    
                System.out.print(encodeArr[i] + " ");   
            }   
            System.out.println();   
            //十六进制编码输出    
            for (int i = 0; i < encodeArr.length; i++) {   
                //FE FF 00 61    
                System.out.print(byteToHex(encodeArr[i]) + " ");   
            }   
            System.out.println();   
            //所占字节数    
            System.out.println(encodeArr.length - 2);//2    
  
        } catch (UnsupportedEncodingException e) {   
            e.printStackTrace();   
        }   
    }   
  
    /**  
     * 以UTF-16写入文件时,也会把文件编码标志FE FF写入文件开头,但写入时不能编一码写一次文件,  
     * 因为这样每次以UTF-16编码时,都会生成编码标志,且写文件时也写入了,这样只需第一次写文件  
     * 时需要的标志却存入了多次,所以当以UTF-16存储字符时,最好一次性编码完成后再写入,或当字  
     * 符太多时,我们用OutputStreamWriter进行包装后可以方便地进行多次写入,而不会多次写入文  
     * 件编码标志,或者我们就用字节流来存,自已负责编码,但从第二次编码后写文件开始,手动去掉文  
     * 件编码标志后再存入也是可以的,只不过没有像直接以字符流多次写入那样方便了。  
     */  
    public void testUTF16File() {   
        try {   
            //--字节流多次写错误   
            byte[] encodeArr = String.valueOf(chineseChar).getBytes("UTF-16");   
            OutputStream o = new FileOutputStream("e:/utf16.txt");   
            o.write(encodeArr);   
            encodeArr = String.valueOf(englishChar).getBytes("UTF-16");   
            o.write(encodeArr);   
            o.close();   
  
            //--读   
            BufferedReader br = new BufferedReader(new InputStreamReader(   
                    new FileInputStream("e:/utf16.txt"), "UTF-16"));   
            //因为存储方法错误,所以导致读取时出现乱码,其实问号就是文件编码标志   
            System.out.println(br.readLine());//中?a   
            br.close();   
  
            //--正确字节流多次写   
            encodeArr = String.valueOf(chineseChar).getBytes("UTF-16");   
            o = new FileOutputStream("e:/utf16.txt");   
            o.write(encodeArr);   
            encodeArr = String.valueOf(englishChar).getBytes("UTF-16");   
            //从第二次开始写入时,不要把文件编码多次写入文件,这样存储会正确   
            o.write(encodeArr, 2, encodeArr.length - 2);//中a   
            o.close();   
  
            //--读   
            br = new BufferedReader(new InputStreamReader(new FileInputStream(   
                    "e:/utf16.txt"), "UTF-16"));   
            System.out.println(br.readLine());//中a   
            br.close();   
  
            //--正确的字符流写   
            OutputStreamWriter ow = new OutputStreamWriter(   
                    new FileOutputStream("e:/utf16.txt"), "UTF-16");   
            ow.write(chineseChar);   
            ow.write(englishChar);   
            ow.close();   
  
            //--读   
            br = new BufferedReader(new InputStreamReader(new FileInputStream(   
                    "e:/utf16.txt"), "UTF-16"));   
            System.out.println(br.readLine());//中a   
            br.close();   
        } catch (UnsupportedEncodingException e) {   
  
            e.printStackTrace();   
        } catch (FileNotFoundException e) {   
            e.printStackTrace();   
        } catch (IOException e) {   
            e.printStackTrace();   
        }   
    }   
  
    /**  
     * 英文字符以UTF-8编码时只占一个字节或二字节(编码大于128小于256的英文字符),编码小于等于128的  
     * 字符UTF-8字符与Unicode编码兼容,中文字符以UTF-8编码时,占三个字节。  
     * 英文、中文使用的UTF-8编码规则模板分别是0xxxxxxx、1110xxxx 10xxxxxx 10xxxxxx  
     * 如"中"字的Unicode编码是4E2D。4E2D在0800-FFFF之间,所以要用上面的三字节规则模板,  
     * 将4E2D写成二进制是:0100 1110 0010 1101,将这个比特流按三字节模板的分段方法分为  
     * 0100 111000 101101,依次代替模板中的x,得到:1110-0100 10-111000 10-101101,  
     * 即 E4 B8 AD,这就是"中"字的UTF8的编码。  
     */  
    public void testCharToUTF8() {   
        try {   
            //--中文字符转UTF-8   
            byte[] encodeArr = String.valueOf(chineseChar).getBytes("UTF-8");   
            //十进制编码输出   
            for (int i = 0; i < encodeArr.length; i++) {   
                //-28 -72 -83   
                System.out.print(encodeArr[i] + " ");   
            }   
            System.out.println();   
            //十六进制编码输出   
            for (int i = 0; i < encodeArr.length; i++) {   
                //E4 B8 AD   
                System.out.print(byteToHex(encodeArr[i]) + " ");   
            }   
            System.out.println();   
            //所占字节数   
            System.out.println(encodeArr.length);//3   
            //--英文字符转UTF-8   
            encodeArr = String.valueOf(englishChar).getBytes("UTF-8");   
            //十进制编码输出   
            for (int i = 0; i < encodeArr.length; i++) {   
                //97   
                System.out.print(encodeArr[i] + " ");   
            }   
            System.out.println();   
            //十六进制编码输出   
            for (int i = 0; i < encodeArr.length; i++) {   
                //61   
                System.out.print(byteToHex(encodeArr[i]) + " ");   
            }   
            System.out.println();   
            //所占字节数   
            System.out.println(encodeArr.length);//1   
  
        } catch (UnsupportedEncodingException e) {   
            e.printStackTrace();   
        }   
    }   
  
    /**  
     * 用Java程序入文件中以UTF-8编码方式存入字符时,是不会在文件头加上编码标志的。  
     * 但如果在windows中用记事本创建一个文件,并以UTF-8保存时,会在文件开开头写  
     * 入文件编码标志 EF BB BF 三个字节长度的编码标志,这时如果使用字节流方式读取  
     * 有编码标示的UTF-8文件时,会有问题,此时只能以字节流读出后去掉前三个字节内容  
     */  
    public void testUTF8File() {   
        try {   
            //--字节流写   
            byte[] encodeArr = String.valueOf(chineseChar).getBytes("UTF-8");   
            OutputStream o = new FileOutputStream("e:/utf8.txt");   
            o.write(encodeArr);   
            encodeArr = String.valueOf(englishChar).getBytes("UTF-8");   
            o.write(encodeArr);   
            o.close();   
  
            //--读   
            BufferedReader br = new BufferedReader(new InputStreamReader(   
                    new FileInputStream("e:/utf8.txt"), "UTF-8"));   
            System.out.println(br.readLine());//中a   
            br.close();   
  
            //--以字符流的方式读取windows记事本创建的有文件编码标志的UTF-8文件时错误   
            br = new BufferedReader(new InputStreamReader(new FileInputStream(   
                    "e:/utf-8-2.txt"), "UTF-8"));   
            System.out.println(br.readLine());//?中a   
            br.close();   
  
            //--以字节流读取有编码标志的UTF-8文件   
            FileInputStream fi = new FileInputStream("e:/utf-8-2.txt");   
            byte[] b = new byte[1024];   
            int readCount = fi.read(b);   
            //手动丢弃前三个字节的内容   
            System.out.println(new String(b, 3, readCount - 3, "UTF-8"));//中a   
            fi.close();   
        } catch (UnsupportedEncodingException e) {   
  
            e.printStackTrace();   
        } catch (FileNotFoundException e) {   
            e.printStackTrace();   
        } catch (IOException e) {   
            e.printStackTrace();   
        }   
    }   
  
    /**  
     * 英文字符以GBK编码时只占一个字节或二字节(编码大于128小于256的英文字符),编码小于等于128的  
     * 字符GBK字符与Unicode编码兼容,中文字符以GBK编码时,占  
     * 两个字节。  
     * GBK对中文编码时,每个字节的最高位都是一  
     */  
    public void testCharToGBK() {   
        try {   
            //--中文字符转GBK   
            byte[] encodeArr = String.valueOf(chineseChar).getBytes("GBK");   
            //十进制编码输出   
            for (int i = 0; i < encodeArr.length; i++) {   
                //-42 -48   
                System.out.print(encodeArr[i] + " ");   
            }   
            System.out.println();   
            //十六进制编码输出   
            for (int i = 0; i < encodeArr.length; i++) {   
                //D6 D0   
                System.out.print(byteToHex(encodeArr[i]) + " ");   
            }   
            System.out.println();   
            //所占字节数   
            System.out.println(encodeArr.length);//2   
            //--英文字符转GBK   
            encodeArr = String.valueOf(englishChar).getBytes("GBK");   
            //十进制编码输出   
            for (int i = 0; i < encodeArr.length; i++) {   
                //97   
                System.out.print(encodeArr[i] + " ");   
            }   
            System.out.println();   
            //十六进制编码输出   
            for (int i = 0; i < encodeArr.length; i++) {   
                //61   
                System.out.print(byteToHex(encodeArr[i]) + " ");   
            }   
            System.out.println();   
            //所占字节数   
            System.out.println(encodeArr.length);//1   
  
        } catch (UnsupportedEncodingException e) {   
            e.printStackTrace();   
        }   
    }   
  
    public void testCharFromUTF16() {   
        try {   
            byte[] encodeArr = String.valueOf(chineseChar).getBytes("UTF-16");   
            System.out.println(new String(encodeArr, "UTF-16"));//中   
  
            encodeArr = new byte[] { -0x2, -0x1, 0x4E, 0x2D };   
            System.out.println(new String(encodeArr, "UTF-16"));//中   
        } catch (UnsupportedEncodingException e) {   
            e.printStackTrace();   
        }   
    }   
  
    public static String byteToHex(byte b) {   
        return Integer.toHexString((b & 0x000000FF) | 0xFFFFFF00).substring(6)   
                .toUpperCase();   
    }   
}  

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值