轉換流也是一種處理流,它提供了字節流和字符流之間的轉換。在Java IO流中提供了兩個轉換流:InputStreamReader 和 OutputStreamWriter,這兩個類都屬於字符流。其中InputStreamReader將字節輸入流轉為字符輸入流,繼承自Reader。OutputStreamWriter是將字符輸出流轉為字節輸出流,繼承自Writer。
眾所周知,計算機中存儲的數據都是二進制的數字,我們在電腦屏幕上看到的文字信息是將二進制轉換之后顯示的,兩者之間存在編碼與解碼的過程,其互相轉換必須遵循某種規則,即編碼和解碼都遵循同一種規則才能將文字信息正常顯示,如果編碼跟解碼使用了不同的規則,就會出現亂碼的情況。
- 編碼:字符、字符串(能看懂的)--字節(看不懂的)
- 解碼:字節(看不懂的)-->字符、字符串(能看懂的)
上面說的編碼與解碼的過程需要遵循某種規則,這種規則就是不同的字符編碼。我們在剛剛學習編程的時候最早接觸就是ASCII碼,它主要是用來顯示英文和一些符號,到后面還有接觸到別的編碼規則常用的有:gb2312,gbk,utf-8等。它們分別屬於不同的編碼集。
我們需要明確的是字符編碼和字符集是兩個不同層面的概念。
- encoding是charset encoding的簡寫,即字符集編碼,簡稱編碼。
- charset是character set的簡寫,即字符集。
編碼是依賴於字符集的,一個字符集可以有多個編碼實現,就像代碼中的接口實現依賴於接口一樣。
轉換流的原理是:字符流 = 字節流 + 編碼表。在轉換流中選擇正確的編碼非常的重要,因為指定了編碼,它所對應的字符集自然就指定了,否則很容易出現亂碼,所以編碼才是我們最終要關心的。
轉換流的特點:其是字符流和字節流之間的橋梁。
可對讀取到的字節數據經過指定編碼轉換成字符
可對讀取到的字符數據經過指定編碼轉換成字節
那么何時使用轉換流?
當字節和字符之間有轉換動作時
流操作的數據需要編碼或解碼時
1、InputStreamReader
InputStreamReader是字節流到字符流的橋梁:它讀取字節,並使用指定的字符集將其解碼為字符。它的字符集可以由名稱指定,也可以接受平台的默認字符集。
構造方法:
- InputStreamReader(InputStream in):創建一個默認字符集字符輸入流。
- InputStreamReader(InputStream in, String charsetName):創建一個指定字符集的字符流。
構造方法示例代碼:
InputStreamReader isr1 = new InputStreamReader(new FileInputStream("D:\\IO\\utf8.txt")); InputStreamReader isr2 = new InputStreamReader(new FileInputStream("D:\\IO\\utf8.txt"),"UTF-8");
InputStreamReader讀入不同編碼舉例(讀入的文件編碼是UTF-8):
package com.thr; import java.io.*; /** * @author Administrator * @date 2020-02-27 * @desc InputStreamReader */ public class InputStreamReaderTest { public static void main(String[] args) { //定義轉換流 InputStreamReader isr = null; InputStreamReader isr1 = null; try { //創建流對象,默認編碼方式 isr = new InputStreamReader(new FileInputStream("D:\\IO\\utf8.txt")); //創建流對象,指定GBK編碼 isr1 = new InputStreamReader(new FileInputStream("D:\\IO\\utf8.txt"),"GBK"); //默認方式打印 int len; char[] buffer = new char[1024]; while ((len=isr.read(buffer))!=-1){ System.out.println(new String(buffer,0,len)); } //GBK編碼方式打印 int len1; char[] buffer1 = new char[1024]; while ((len1=isr1.read(buffer1))!=-1){ System.out.println(new String(buffer1,0,len1)); } System.out.println("成功..."); } catch (IOException e) { e.printStackTrace(); } finally { //釋放資源,先使用的后關閉 if (isr1!=null){ try { isr1.close(); } catch (IOException e) { e.printStackTrace(); } } if (isr!=null){ try { isr.close(); } catch (IOException e) { e.printStackTrace(); } } } } } //運行結果: --UTF-8 武漢加油 中國加油 齊心協力 戰勝疫情 --GBK 鍩挎奼夊姞娌� 涓浗鍔犳補 榻愬績鍗忓姏 鎴樿儨鐤儏
可以發現,UTF-8編碼沒有出現亂碼,而GBK編碼出現了亂碼,這是因為是在IDEA編輯器下打印的,我的IDEA編輯器設置的默認編碼是UTF-8。而UTF-8的編碼集是Unicode,GBK的編碼集是GBK,兩者並沒有通過轉換,所以GBK編碼在Unicode集上打印出現了亂碼。
2、OutputStreamWriter
OutputStreamWriter是字符流通向字節流的橋梁:用指定的字符集將字符編碼為字節。它的字符集可以由名稱指定,也可以接受平台的默認字符集。
構造方法:
- OutputStreamWriter(OutputStream in): 創建一個使用默認字符集的字符流。
- OutputStreamWriter(OutputStream in, String charsetName): 創建一個指定字符集的字符流。
構造方法示例代碼:
OutputStreamWriter isr1 = new OutputStreamWriter(new FileOutputStream("D:\\IO\\gbk.txt"")); OutputStreamWriter isr2 = new OutputStreamWriter(new FileOutputStream("D:\\IO\\gbk1.txt") , "GBK");
OutputStreamWriter讀出不同編碼舉例:
package com.thr; import java.io.*; /** * @author Administrator * @date 2020-02-27 * @desc OutputStreamWriter */ public class OutputStreamReaderTest { public static void main(String[] args) { //定義轉換流 OutputStreamWriter osw = null; OutputStreamWriter osw1 = null; try { osw = new OutputStreamWriter(new FileOutputStream("D:\\IO\\gbk.txt")); osw1 = new OutputStreamWriter(new FileOutputStream("D:\\IO\\gbk1.txt"),"GBK"); //以默認格式寫出 osw.write("武漢加油,中國加油"); //以GBK格式寫出 osw1.write("武漢加油,中國加油"); System.out.println("成功..."); } catch (IOException e) { e.printStackTrace(); } finally { //釋放資源,先使用的后關閉 if (osw1!=null){ try { osw1.close(); } catch (IOException e) { e.printStackTrace(); } } if (osw!=null){ try { osw.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
我們運行完后發現並沒有亂碼,這是因為Windows系統默認支持了UTF-8和GBK字符集。可以將輸出的路徑改為當前項目下 new FileOutputStream(“gbk.txt”);然后用Idea打開就可以看成差別來了。
3、轉換文件編碼
將UTF-8編碼的文本文件,轉換為GBK編碼的文本文件。
1、指定UTF-8編碼的轉換流,讀取文本文件。
2、使用GBK編碼的轉換流,寫出文本文件。
package com.thr; import java.io.*; /** * @author Administrator * @date 2020-02-27 * @desc 將讀入UTF-8文件轉換為GBK */ public class ConversionStreamTest { public static void main(String[] args) { //定義轉換流 InputStreamReader isr = null; OutputStreamWriter osw = null; try { //創建流對象,指定GBK編碼 isr = new InputStreamReader(new FileInputStream("D:\\IO\\utf8.txt"),"UTF-8"); osw = new OutputStreamWriter(new FileOutputStream("gbk.txt"),"GBK"); int len; char[] buffer = new char[1024]; while ((len=isr.read(buffer))!=-1){ osw.write(buffer,0,len); } System.out.println("成功..."); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { //釋放資源 if (osw!=null){ try { osw.close(); } catch (IOException e) { e.printStackTrace(); } } if (isr!=null){ try { isr.close(); } catch (IOException e) { e.printStackTrace(); } } } } }