1. 程式人生 > >J07-Java IO流總結七 《 InputStreamReader和OutputStreamWriter 》

J07-Java IO流總結七 《 InputStreamReader和OutputStreamWriter 》

trace encoder div 字節數 否則 all args system.in 兩個

  

  前面在介紹FileReader和FileWriter的時候有說到,FileReader的讀取字符功能,以及FileWriter的寫出字符的功能,都不是它們自己實現的,而是,它們分別繼承了InputStreamReader和OuputStreamWriter這兩個轉換流,利用這兩個轉換流,實現了字節數據與字符數據之間的轉換,關於這點可以通過FileReader和FileWriter的源碼看出來。

  下面將介紹這兩個轉換流,並分別通過幾個簡單的應用場景來熟悉它們的用法。

1. InputStreamReader

1.1 概念介紹

  InputStreamReader將底層的字節數據轉換為字符數據

,可以顯式的或者使用平臺默認的字符集進行轉換。所有的字符流的轉換工作都依賴於它來完成。

  根據API文檔的描述,InputStreamReader 是字節流通向字符流的橋梁,它使用指定的 charset 讀取字節並將其解碼為字符。它使用的字符集可以由名稱指定或顯式給定,或者可以接受平臺默認的字符集。

每次調用 InputStreamReader 中的一個 read() 方法都會導致從底層輸入流讀取一個或多個字節。要啟用從字節到字符的有效轉換,可以提前從底層流讀取更多的字節,使其超過滿足當前讀取操作所需的字節。

  為了達到最高效率,可要考慮在 BufferedReader 內包裝 InputStreamReader。例如:

BufferedReader in
   = new BufferedReader(new InputStreamReader(System.in));

關於源碼:

  InputStreamReader的源碼比較簡單,它有一個非常重要的成員變量:

private final StreamDecoder sd;

  InputStreamReader的主要實現都調用了這個流解碼類StreamDecoder,它只有這一個成員變量,而這一個類把它的所有操作都包括了。StreamDecoder的主要作用是獲取一個字節輸入流InputStream,然後根據給定的編碼方案讀取字符,如果沒有給定,則默認是系統編碼。

  由源碼可知,InputStreamReader的設計使用到了裝飾設計模式,它本身並沒有提供啥功能,具體的實現其實都由StreamDecoder來實現了。

  源碼中關於InputStreamReader的幾個構造方法需要格外註意一下,因為通過它的構造方法,可以顯式的指定解碼所需的字符集:

技術分享圖片

1.2 應用示例

  System.in是字節流對象,代表鍵盤的輸入,如果我們想按行接收用戶的輸入時,就必須用到緩沖字符流BufferedReader特有的方法readLine(),但是經過觀察會發現在創建BufferedReader的構造方法的參數必須是一個Reader對象,如下:

public BufferedReader(Reader in)

這時候我們的轉換流InputStreamReader就派上用場了。

示例代碼如下所示:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class InputStreamReaderTest {
    public static void main(String[] args) {
        BufferedReader br = null;
        
        String str = null;
        try {
            br = new BufferedReader(new InputStreamReader(System.in));
            while(!"exit".equals(str = br.readLine())) {
                System.out.println(str);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

代碼運行效果:

技術分享圖片

2. OutputStreamWriter

2.1 概念介紹

  OutputStreamWriter是將字符數據轉換為字節數據的流。可以顯式的或者使用平臺默認的字符集進行轉換。所有的字符輸出流的轉換工作都依賴於它來完成

  根據API文檔的描述,OutputStreamWriter 是字符流通向字節流的橋梁:可使用指定的 charset 將要寫入流中的字符編碼成字節。它使用的字符集可以由名稱指定或顯式給定,否則將接受平臺默認的字符集。

  每次調用 write() 方法都會導致在給定字符(或字符集)上調用編碼轉換器。在寫入底層輸出流之前,得到的這些字節將在緩沖區中累積。可以指定此緩沖區的大小,不過,默認的緩沖區對多數用途來說已足夠大。註意,傳遞給 write() 方法的字符沒有緩沖。

  為了獲得最高效率,可考慮將 OutputStreamWriter 包裝到 BufferedWriter 中,以避免頻繁調用轉換器。例如:

Writer out
   = new BufferedWriter(new OutputStreamWriter(System.out));

源碼:

  閱讀OutputStreamWriter的源碼,可以發現它跟InputStreamReader一樣使用了裝飾器模式,在它的類當中,持有了一個的引用StreamEncoder的應用,StreamEncoder可以理解為一個編碼器,當調用OutputStreamWriter的write、close方法時,實際上底層調用的還是這個StreamEncoder的方法。

  需要留意一下OutputStreamWriter的構造方法:

技術分享圖片

2.2 應用示例

  System.out是字節流對象,代表輸出到顯示器,在上面的示例中按行讀取用戶的輸入後,並且要將讀取的一行字符串直接顯示到控制臺,就需要用到字符流的write(String str)方法,所以我們要使用OutputStreamWriter將字符流轉化為字節流。

示例代碼如下所示:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

public class ConvertStreamTest {
    public static void main(String[] args) {
        BufferedReader br = null;
        BufferedWriter bw = null;
        
        String str = null;
        try {
            br = new BufferedReader(new InputStreamReader(System.in));
            bw = new BufferedWriter(new OutputStreamWriter(System.out));
            
            while(!"bye".equals(str = br.readLine())) {
                bw.write("-->" + str);
                bw.newLine();
                bw.flush();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

代碼運行效果:

技術分享圖片

3 轉換流綜合應用示例

  下面的示例代碼中定義了兩個方法,分別為Utf8ToGbk()和gbkToUtf8(),其中,Utf8ToGbk()實現了從一個用UTF-8編碼的源文件復制數據到一個用GBK編碼的目標文件,gbkToUtf8()方法則正好反之。

示例代碼:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;

public class ConvertTest {
    public static void main(String[] args) {
//      gbkToUtf8();
        Utf8ToGbk();

    }

    ////////////////////////////////////////////////////////////
    private static void Utf8ToGbk() {
        BufferedReader br = null;
        BufferedWriter bw = null;
        
        try {
            br = new BufferedReader(new InputStreamReader(new FileInputStream("./src/res/2_copy.txt"), "utf-8"));
            bw = new BufferedWriter(new FileWriter("./src/res/2.txt"));
//            bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("./src/res/2.txt")));
            
            String str = null;
            while(null != (str = br.readLine())) {
                bw.write(str);
                bw.newLine();
            }
            
            
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(null != bw) {
                try {
                    bw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(null != br) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    ////////////////////////////////////////////////////////////
    private static void gbkToUtf8() {
        BufferedReader br = null;
        BufferedWriter bw = null;
        
        try {
            br = new BufferedReader(new FileReader("./src/res/2.txt"));
//          br = new BufferedReader(new InputStreamReader(new FileInputStream("./src/res/2.txt")));//使用默認字符集

            bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("./src/res/2_copy.txt"), "utf-8"));
            
            String str = null;
            while(null != (str = br.readLine())) {
                bw.write(str);
                bw.newLine();
            }
            
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(null != bw) {
                try {
                    bw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(null != br) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

J07-Java IO流總結七 《 InputStreamReader和OutputStreamWriter 》