天天看點

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,美國資訊交換标準代碼)是基于拉丁字母的一套電腦編碼系統,用于顯示現代英語,主要包括控制字元(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