字符流

124 阅读3分钟

「这是我参与11月更文挑战的第6天,活动详情查看:2021最后一次更文挑战

思考:既然字节流可以操作所有文件,那么为什么还要学习字符流?

  1. 如果利用字节流,把文本文件中的中文,读取到内存中,有可能出现乱码?
  2. 如果利用字节流,把中文写到文本文件中,也有可能出现乱码。

编码表:

基础知识:

  1. 计算机中存储的信息都是用二进制数来表示的。

  2. 按照某种规则,将字符变成二进制,再存储到计算机中,称为编码。

  3. 按照同样的规则,将存储在计算机中的二进制数,解析显示出来,称为编码。

  4. 编码和解码的方式必须一致,否则会导致乱码。

简单理解: 存储一个字符a,首先需在码表中查到对应的数字是97,然后转换成二进制进行存储。 读取的时候,先把二进制解析出来,再转成97,通过97查找到对应的字符是a。

编码表:

ASCII 字符集:

ASCII: 包括了数字,大小写字符和一些常见的标点符号。

注意:ASCII 码表中 是没有中文的。

GBK: window系统默认的码表,兼容ASCII码表,也包含了 21003个汉字,并支持整体汉字以及部分日韩文字。

注意:GBK 是中国的码表,一个中文以两个字节的形式存储。但不包含世界上所有国家的文字。

编码表:

Unicode码表:

由国际组织ISO制定,是统一的万国码,计算机科学领域里的一项业界标准,容纳世界上大多数国家的所有常见文字和符号。

但是因为表示的字符太多,所以Unicode 码表中的数字不是直接以二进制的形式存储到计算机的。

会先通过UTF-7, UTF-7.5, UTF-8, UTF-16, 以及UTF-32进行编码,再存储到计算机,其中最为常见的就是UTF-8.

注意: Unicode 是万国码, 以 UTF-8 编码后一个中文以三个字节的形式存储。

image.png

image.png

字符串中的编码解码问题


public class CharStreamDemo2 {
    public static void main(String[] args) throws UnsupportedEncodingException {
        String s = "你好啊";
        byte[] bytes = s.getBytes();
        System.out.println(Arrays.toString(bytes));
        byte[] bytes2 = s.getBytes("UTF-8");
        System.out.println(Arrays.toString(bytes2));

        byte[] bytes3 = s.getBytes("GBK");
        System.out.println(Arrays.toString(bytes3));

        byte[] bytes4 = {-28, -67, -96, -27, -91, -67, -27, -107, -118};
        byte[] bytes5 = {-60, -29, -70, -61, -80, -95};

        // 默认utf-8解码
        String s1 = new String(bytes4);
        System.out.println(s1);

        // gbk 解码
        String s2 = new String(bytes5,"gbk");
        System.out.println(s2);

    }
}

为什么字节流读取文本文件,可能出现乱码?

因为字节流一次读一个字节,而不管GBK还是UTF-8 一个中文都是多个字节,用字节流每次只能读其中的一部分,所以就会出现乱码问题。

public class CharStreamDemo3 {
    public static void main(String[] args) throws IOException {
        // 创建字符输出流的对象
        FileWriter fw = new FileWriter("a.txt");
        // 写出数据
        // 写一个字符
//        fw.write(97);
//        fw.write(98);
//        fw.write(99);

        // 写出一个字符数组
//        char [] chars = {97,98,99,100};
//        fw.write(chars);
//
        //写出字符数组的一部分
//        char [] chars = {97,98,99,100};
//        fw.write(chars,1,3);
        
        // 写一个字符串
//        String line = "kjfsdkdsf";
//        fw.write(line);
        
        // 写一个字符串的一部分
        String line = "ddsds";
        fw.write(line,0,2);
        
        // 释放资源
        fw.close();
    }
}