天天看点

Java基础之IO转换流学习简要概述字符集转换流参考链接

Java基础之IO转换流学习

  • 简要概述
  • 字符集
    • 介绍
    • 分类
    • 乱码举例
  • 转换流
    • InputStreamReader类(字节流->字符流)
    • OutputStreamWriter类(字符流->字节流)
    • 注意事项
  • 参考链接

简要概述

  • 作用
    Java基础之IO转换流学习简要概述字符集转换流参考链接
  • 字符编码与解码
    字符编码(Character Encoding):就是一套自然语言的字符与二进制数之间的对应规则。
    编码表:则是生活中文字和计算机中二进制的对应规则。

    计算机中储存的信息都是用二进制数表示的,而我们在屏幕上看到的数字、英文、标点符号、汉字等字符是二进制数转换之后的结果。

    编码:按照某种规则,将字符存储到计算机中(字符(能看懂的)–字节(看不懂的))

    解码:将存储在计算机中的二进制数按照某种规则解析显示出来,称为解码(字节(看不懂的)–>字符(能看懂的))

    // 编码:通过指定的字符集解码字节数组 byte[] -- String
        public String(byte bytes[], String charsetName)
                throws UnsupportedEncodingException {
            this(bytes, 0, bytes.length, charsetName);
        }
    
        // 解码:使用指定的字符集合把字符串编码为字节数组 String -- byte[]
        public byte[] getBytes(String charsetName)
            throws UnsupportedEncodingException {
            if (charsetName == null) throw new NullPointerException();
            return StringCoding.encode(charsetName, value, 0, value.length);
        }
    
               

字符集

介绍

  • 概念

    字符集(Charset):也叫编码表。是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等。

    计算机要准确的存储和识别各种字符集符合,需要进行字符编码,一套字符集必然至少有一套字符编码。常见字符集有ASCII字符集、GBK字符集、Unicode字符集等。

    当指定了编码,它对应的字符集自然就指定了。

分类

  • ASCII字符集

    ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)是基于拉丁字母的一套电脑编码系统,用于显示现代英语,主要包括控制字符(回车键、退格、换行键等)和可显示字符(英文大小写字符、阿拉伯数字和西文符号)。

    基本的ASCII字符集,使用7位(bits)表示一个字符,共128字符。ASCII的扩展字符集使用8位(bits)表示一个字符,共256字符,方便支持欧洲常用字符。

  • ISO-8859-1字符集

    拉丁码表,别名Latin-1,用于显示欧洲使用的语言,包括荷兰、丹麦、德语、意大利语、西班牙语等。

    ISO-8859-1使用单字节编码,兼容ASCII编码。

  • GBxxx字符集

    GB就是国标的意思,是为了显示中文而设计的一套字符集。

    GB2312:简体中文码表。一个小于127的字符的意义与原来相同。但两个大于127的字符连在一起时,就表示一个汉字,这样大约可以组合了包含7000多个简体汉字,此外数学符号、罗马希腊的字母、日文的假名们都编进去了,连在ASCII里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的"全角"字符,而原来在127号以下的那些就叫"半角"字符了。

    GBK:最常用的中文码表。是在GB2312标准基础上的扩展规范,使用了双字节编码方案,共收录了21003个汉字,完全兼容GB2312标准,同时支持繁体汉字以及日韩汉字等。

    GB18030:最新的中文码表。收录汉字70244个,采用多字节编码,每个字可以由1个、2个或4个字节组成。支持中国国内少数民族的文字,同时支持繁体汉字以及日韩汉字等。

  • Unicode字符集

    Unicode编码系统为表达任意语言的任意字符而设计,是业界的一种标准,也称为统一码、标准万国码。

    它最多使用4个字节的数字来表达每个字母、符号,或者文字。有三种编码方案:UTF-8、UTF-16和UTF-32。最为常用的UTF-8编码。

    UTF-8编码,可以用来表示Unicode标准中任何字符,它是电子邮件、网页及其他存储或传送文字的应用中,优先采用的编码。互联网工程工作小组(IETF)要求所有互联网协议都必须支持UTF-8编码。所以,我们开发Web应用,也要使用UTF-8编码。它使用一至四个字节为每个字符编码,编码规则:

    128个US-ASCII字符,只需一个字节编码。

    拉丁文等字符,需要二个字节编码。

    大部分常用字(含中文),使用三个字节编码。

    其他极少使用的Unicode辅助字符,使用四字节编码

乱码举例

  • 文本编码与读取编码不一致

    IDEA设置,都是默认的UTF-8编码,但是,当读取Windows系统中创建的文本文件时,由于Windows系统的默认是GBK编码,就会出现乱码

    /**
        * @Author charlesYan
        * @Description //测试乱码情况:源文件采用gbk编码,读取时采用utf-8解码
        * @Date 11:11 2020/11/17
        * @Param []
        * @return void
        **/
        @Test
        public void testUnintelligible(){
    
            try (FileReader fr = new FileReader("E:\\Blog\\202011171130.txt");
                FileInputStream fis = new FileInputStream("E:\\Blog\\202011171130.txt");) {
    
                int len;
    
                while ((len = fr.read()) != -1) {
                    System.out.println((char) len);
                }
    
                // 定义字节数组
                byte[] b = new byte[1024];
    
                // 定义长度
                int length;
    
                while ((length = fis.read(b)) != -1) {
                    System.out.println(new String(b,0,length));
                }
                
    
            } catch (Exception e) {
                e.printStackTrace();
            }
    
        }
    
    
               

转换流

InputStreamReader类(字节流->字符流)

  • 简介

    转换流java.io.InputStreamReader,是Reader的子类,从字面意思可以看出它是从字节流到字符流的桥梁。它读取字节,并使用指定的字符集将其解码为字符。它的字符集可以由名称指定,也可以接受平台的默认字符集。

  • 构造方法
    InputStreamReader(InputStream in): 创建一个使用默认字符集的字符流。
        InputStreamReader(InputStream in, String charsetName): 创建一个指定字符集的字符流。
    
    
               
  • 使用转换流解决编码问题
    /**
        * @Author charlesYan
        * @Description //使用转换流读取数据,解决读取乱码问题
        * @Date 14:41 2020/11/17
        * @Param []
        * @return void
        **/
        @Test
        public void testInputStreamReader(){
    
            // 文件路径内容采用gbk编码,创建流对象指定GBK编码
            try(InputStreamReader isr = new InputStreamReader(new FileInputStream("E:\\Blog\\202011171112.txt"), "GBK");) {
    
                // 定义变量,保存字符
                int read;
    
                // 使用指定编码字符流读取,正常解析
                while ((read = isr.read()) != -1) {
                    System.out.println((char)read);
                }
    
            } catch (Exception e) {
                e.printStackTrace();
            }
    
        }
    
    
               

OutputStreamWriter类(字符流->字节流)

  • 简介

    转换流java.io.OutputStreamWriter ,是Writer的子类,字面看容易混淆会误以为是转为字符流,其实不然,OutputStreamWriter为从字符流到字节流的桥梁。使用指定的字符集将字符编码为字节。它的字符集可以由名称指定,也可以接受平台的默认字符集

  • 构造方法
    OutputStreamWriter(OutputStream in): 创建一个使用默认字符集的字符流。
        OutputStreamWriter(OutputStream in, String charsetName): 创建一个指定字符集的字符流。
    
    
    
               
  • 指定编码构造文件
    /**
        * @Author charlesYan
        * @Description //使用转换流构造指定编码文件
        * @Date 14:56 2020/11/17
        * @Param []
        * @return void
        **/
        @Test
        public void testOutputStreamWriter() throws Exception {
    
            // 此时创建的文件必须以UTF-8格式打开,否则乱码
            OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("E:\\Blog\\202011171500.txt"));
    
            String content = "你好";// 保存为6个字节
            osw.write(content);
            osw.close();
    
            // 此时创建的文件必须以GBK格式打开,否则乱码
            OutputStreamWriter gbkOsw = new OutputStreamWriter(new FileOutputStream("E:\\Blog\\202011171501.txt"), "GBK");
            String substance = "明天";// 保存为4个字节
            gbkOsw.write(substance);
            gbkOsw.close();
        }
    
    
    
    
               

注意事项

  • 提高效率

    为了达到最高效率,可以考虑在 BufferedReader 内包装 InputStreamReader

    BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream("E:\\Blog\\202011171501.txt")));
    
               
  • FileReader类仅仅是InputStreamReader的简单衍生并未扩展任何功能
  • FileReader类读取数据实质是InputStreamReader类在读取,而InputStreamReader读取数据实际是StreamDecoder类读取,因此在使用字符输入流的时候实际是StreamDecoder类在发挥作用

参考链接

  • 史上最骚最全最详细的IO流教程,没有之一!

    https://www.cnblogs.com/yichunguo/p/11775270.html

  • JAVA基础知识之InputStreamReader流

    https://blog.csdn.net/ai_bao_zi/article/details/81133476