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