Java基礎之IO轉換流學習

Charles Yan發表於2020-11-17

簡要概述

  • 作用
    轉換流作用

  • 字元編碼與解碼

    字元編碼(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,美國資訊交換標準程式碼)是基於拉丁字母的一套電腦編碼系統,用於顯示現代英語,主要包括控制字元(Enter鍵、退格、換行鍵等)和可顯示字元(英文大小寫字元、阿拉伯數字和西文符號)。

    基本的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

相關文章