Java字符集编码与解码

Java字符集编码与解码

字符(Character)是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。字符集(Character set)是多个字符的集合,字符集种类较多,每个字符集包含的字符个数不同,常见字符集名称:ASCII字符集、GB2312字符集、BIG5字符集、 GB18030字符集、Unicode字符集等。计算机要准确的处理各种字符集文字,就需要进行字符编码,以便计算机能够识别和存储各种文字。

1、ASCII字符集

ASCII ((American Standard Code for Information Interchange): 美国信息交换标准代码)是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧语言。它是最通用的信息交换标准,并等同于国际标准ISO/IEC 646。ASCII第一次以规范标准的类型发表是在1967年,最后一次更新则是在1986年,到目前为止共定义了128个字符。字符集ASCII不支持中文。

import java.nio.charset.Charset;
import java.util.Arrays;

public class TestCharacterSet {
    public static void main(String[] args) {
        //ASCII字符集编码不支持中文字符,如果遇到中文字符,则用?的编码63来代替
        byte[] asciis = "我".getBytes(Charset.forName("ASCII"));
        byte[] asciis2 = "是".getBytes(Charset.forName("ASCII"));
        byte[] asciis3 = "谁".getBytes(Charset.forName("ASCII"));
        System.out.println(Arrays.toString(asciis));//[63]
        System.out.println(Arrays.toString(asciis2));//[63]
        System.out.println(Arrays.toString(asciis3));//[63]
        String ascii = new String(asciis, Charset.forName("ASCII"));
        System.out.println(ascii);//?
        //将数字强转为char类型,用的就是ASCII码
        System.out.println((char)63);//?
    }
}

2、GBK字符集

import java.nio.charset.Charset;
import java.util.Arrays;

public class TestCharacterSet {
    public static void main(String[] args) {
        //GBK字符集编码是支持中文的,一个中文字符用两个字节表示
        byte[] gbks1 = "我".getBytes(Charset.forName("GBK"));
        byte[] gbks2 = "是".getBytes(Charset.forName("GBK"));
        byte[] gbks3 = "谁".getBytes(Charset.forName("GBK"));
        System.out.println(Arrays.toString(gbks1));//[-50, -46]
        System.out.println(Arrays.toString(gbks2));//[-54, -57]
        System.out.println(Arrays.toString(gbks3));//[-53, -83]
        //解码
        String gbk1 = new String(gbks1, Charset.forName("GBK"));
        String gbk2 = new String(gbks2, Charset.forName("GBK"));
        String gbk3 = new String(gbks3, Charset.forName("GBK"));
        System.out.println(gbk1);//我
        System.out.println(gbk2);//是
        System.out.println(gbk3);//谁
    }
}

3、UTF-8字符集

import java.nio.charset.Charset;
import java.util.Arrays;

public class TestCharacterSet {
    public static void main(String[] args) {
        //UTF-8字符集编码是现在很常用的编码,一个中文字符常用三个字节表示
        Charset charset = Charset.forName("UTF-8");
        byte[] bytes1 = "我".getBytes(charset);
        byte[] bytes2 = "是".getBytes(charset);
        byte[] bytes3 = "谁".getBytes(charset);
        System.out.println(Arrays.toString(bytes1));//[-26, -120, -111]
        System.out.println(Arrays.toString(bytes2));//[-26, -104, -81]
        System.out.println(Arrays.toString(bytes3));//[-24, -80, -127]
        //解码
        String s1 = new String(bytes1, charset);
        String s2 = new String(bytes2, charset);
        String s3 = new String(bytes3, charset);
        System.out.println(s1);//我
        System.out.println(s2);//是
        System.out.println(s3);//谁
    }
}

4、编码和解码的字符集不同时

乱码且字节丢失,无法还原

import java.nio.charset.Charset;
import java.util.Arrays;

public class TestCharacterSet {
    public static void main(String[] args) {
        Charset gbk = Charset.forName("GBK");
        Charset utf_8 = Charset.forName("UTF-8");
        //用GBK字符集编码
        byte[] bytes = "我".getBytes(gbk);
        System.out.println(Arrays.toString(bytes));//[-50, -46]
        //用UTF-8字符集解码
        String s = new String(bytes, utf_8);
        System.out.println(s);//��
        //用UTF-8编码
        byte[] bytes1 = s.getBytes(utf_8);
        System.out.println(Arrays.toString(bytes1));//[-17, -65, -67, -17, -65, -67]
        //可见当utf-8无法正常解码的时候,就会用�的编码来代替
        //再用GBK解码
        String s1 = new String(bytes1,gbk);
        System.out.println(s1);//锟斤拷
    }
}
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class TestCharacterSet {
    public static void main(String[] args) {
        Charset gbk = Charset.forName("GBK");
        Charset utf_8 = Charset.forName("UTF-8");
        //用GBK字符集编码
        byte[] bytes = "我是".getBytes(gbk);
        System.out.println(Arrays.toString(bytes));//[-50, -46, -54, -57]
        System.out.println(byteArrToBinary(bytes));
        //[11001110, 11010010, 11001010, 11000111]
        //用UTF-8字符集解码
        String s = new String(bytes, utf_8);
        System.out.println(s);//��
        //用UTF-8编码
        byte[] bytes1 = s.getBytes(utf_8);
        System.out.println(Arrays.toString(bytes1));
        //[-17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67]
        System.out.println(byteArrToBinary(bytes1));
        //[11101111, 10111111, 10111101, 11101111, 10111111, 10111101, 
        // 11101111, 10111111, 10111101, 11101111, 10111111, 10111101]
        //可见当utf-8无法正常解码的时候,就会用�的编码来代替
        //再用GBK解码
        String s1 = new String(bytes1,gbk);
        System.out.println(s1);//锟斤拷锟斤拷
    }
    private static List byteArrToBinary(byte[] bytes){
        List<String> list = new ArrayList<>();
        int length = bytes.length;
        for (int i = 0;i<length;i++){
            String s = byteToBinary(bytes[i]);
            list.add(s);
        }
        return list;
    }

    /**
     * 字节转二进制
     */
    private static String byteToBinary(byte b){
        String s = Integer.toBinaryString(b & 0xFF);
        return s;
    }
}

乱码,无字节丢失,可以还原

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class TestCharacterSet {
    public static void main(String[] args) {
        Charset gbk = Charset.forName("GBK");
        Charset utf_8 = Charset.forName("UTF-8");
        //用UTF-8字符集编码
        byte[] bytes = "我是谁".getBytes(utf_8);
        System.out.println(Arrays.toString(bytes));//[-26, -120, -111, -26, -104, -81, -24, -80, -127]
        System.out.println(byteArrToBinary(bytes));
        //[11100110, 10001000, 10010001, 11100110, 10011000, 10101111, 11101000, 10110000, 10000001]
        //用GBK字符集解码
        String s = new String(bytes, gbk);
        System.out.println(s);//鎴戞槸璋�
        //用GBK编码
        byte[] bytes1 = s.getBytes(gbk);
        System.out.println(Arrays.toString(bytes1));
        //[-26, -120, -111, -26, -104, -81, -24, -80, 63]
        System.out.println(byteArrToBinary(bytes1));
        //[11100110, 10001000, 10010001, 11100110, 10011000, 10101111, 11101000, 10110000, 111111]
        //再用UTF-8解码
        String s1 = new String(bytes1,utf_8);
        System.out.println(s1);//我是�?
        //可见在没有字节丢失的情况下,选择正确的编码之后可以还原,而最后一个字因为字节丢失,无法还原。
    }
    private static List byteArrToBinary(byte[] bytes){
        List<String> list = new ArrayList<>();
        int length = bytes.length;
        for (int i = 0;i<length;i++){
            String s = byteToBinary(bytes[i]);
            list.add(s);
        }
        return list;
    }

    /**
     * 字节转二进制
     */
    private static String byteToBinary(byte b){
        String s = Integer.toBinaryString(b & 0xFF);
        return s;
    }
}

5、UTF-8编码规则

UTF-8是一种变长字节编码方式。对于某一个字符的UTF-8编码,如果只有一个字节则其最高二进制位为0;如果是多字节,其第一个字节从最高位开始,连续的二进制位值为1的个数决定了其编码的位数,其余各字节均以10开头。UTF-8最多可用到6个字节。
如表:
1字节 0xxxxxxx
2字节 110xxxxx 10xxxxxx
3字节 1110xxxx 10xxxxxx 10xxxxxx
4字节 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
5字节 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
6字节 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
因此UTF-8中可以用来表示字符编码的实际位数最多有31位,即上表中x所表示的位。除去那些控制位(每字节开头的10等),这些x表示的位与UNICODE编码是一一对应的,位高低顺序也相同。
实际将UNICODE转换为UTF-8编码时应先去除高位0,然后根据所剩编码的位数决定所需最小的UTF-8编码位数。
因此那些基本ASCII字符集中的字符(UNICODE兼容ASCII)只需要一个字节的UTF-8编码(7个二进制位)便可以表示。

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class TestCharacterSet {
    public static void main(String[] args) {
        Charset gbk = Charset.forName("GBK");
        Charset utf_8 = Charset.forName("UTF-8");
        //用UTF-8字符集编码
        byte[] bytes = "A".getBytes(utf_8);
        System.out.println(Arrays.toString(bytes));//[65]
        System.out.println(byteArrToBinary(bytes));
        //[1000001]
        //用GBK字符集解码
        String s = new String(bytes, gbk);
        System.out.println(s);//A
        //用GBK编码
        byte[] bytes1 = s.getBytes(gbk);
        System.out.println(Arrays.toString(bytes1));
        //[65]
        System.out.println(byteArrToBinary(bytes1));
        //[1000001]
        //再用UTF-8解码
        String s1 = new String(bytes1,utf_8);
        System.out.println(s1);//A
    }
    private static List byteArrToBinary(byte[] bytes){
        List<String> list = new ArrayList<>();
        int length = bytes.length;
        for (int i = 0;i<length;i++){
            String s = byteToBinary(bytes[i]);
            list.add(s);
        }
        return list;
    }

    /**
     * 字节转二进制
     */
    private static String byteToBinary(byte b){
        String s = Integer.toBinaryString(b & 0xFF);
        return s;
    }
}

正是由于这样的编码规则,当遇到不符合utf-8编码规则的字节的时候,则会用特殊的符号代替。而英文字符在多个字符集编码中的编码与ASCII一致,所以没有出现英文乱码的情况。

6、字节流转字符流

创建一个txt文件,名为 测试.txt ,编码设置为UTF-8。

测试一下
字节流转字符流
编码问题

在这种文件名是中文的情况下,注意Java文件的编码与该文件的编码一致,也为UTF-8。

import java.io.*;

public class TestCharacterSet {
    public static void main(String[] args) throws IOException {
        //字节流
        FileInputStream inputStream = new FileInputStream(new File("D:/测试.txt"));
        //转换成字符流
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream,"UTF-8"));
        //读取
        String line = null;
        while ((line=reader.readLine())!=null){
            //打印
            System.out.println(line);
        }
    }
}

在从字节流转换成字符流的时候,建议顺手设定好字符集编码规则。最好是各个文件的编码规则一致,不然会有乱码的风险。

控制台打印:

测试一下
字节流转字符流
编码问题
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值