天天看點

面試官:說說你對IO中的緩沖流了解

作者:會寫Java的阿偉

緩沖流

基本介紹

緩沖流可以提高位元組流和字元流的讀寫資料的性能

緩沖流分為四類:

  • BufferedInputStream:位元組緩沖輸入流,可以提高位元組輸入流讀資料的性能
  • BufferedOutStream:位元組緩沖輸出流,可以提高位元組輸出流寫資料的性能
  • BufferedReader:字元緩沖輸入流,可以提高字元輸入流讀資料的性能
  • BufferedWriter:字元緩沖輸出流,可以提高字元輸出流寫資料的性能

位元組緩沖輸入

位元組緩沖輸入流:BufferedInputStream

作用:可以把低級的位元組輸入流包裝成一個進階的緩沖位元組輸入流管道,提高位元組輸入流讀資料的性能

構造器:public BufferedInputStream(InputStream in)

原理:緩沖位元組輸入流管道自帶了一個 8KB 的緩沖池,每次可以直接借用作業系統的功能最多提取 8KB 的資料到緩沖池中去,以後我們直接從緩沖池讀取資料,是以性能較好

public class BufferedInputStreamDemo01 {
    public static void main(String[] args) throws Exception {
        // 1.定義一個低級的位元組輸入流與源檔案接通
        InputStream is = new FileInputStream("Demo/src/test.txt");
        // 2.把低級的位元組輸入流包裝成一個進階的緩沖位元組輸入流。
        BufferInputStream bis = new BufferInputStream(is);
        // 3.定義一個位元組數組按照循環讀取。
        byte[] buffer = new byte[1024];
        int len;
        while((len = bis.read(buffer)) != -1){
            String rs = new String(buffer, 0 , len);
            System.out.print(rs);
        }
    }
}
           

位元組緩沖輸出

位元組緩沖輸出流:BufferedOutputStream

作用:可以把低級的位元組輸出流包裝成一個進階的緩沖位元組輸出流,進而提高寫資料的性能

構造器:public BufferedOutputStream(OutputStream os)

原理:緩沖位元組輸出流自帶了 8KB 緩沖池,資料就直接寫入到緩沖池中去,性能提高了

public class BufferedOutputStreamDemo02 {
    public static void main(String[] args) throws Exception {
        // 1.寫一個原始的位元組輸出流
        OutputStream os = new FileOutputStream("Demo/src/test.txt");
        // 2.把低級的位元組輸出流包裝成一個進階的緩沖位元組輸出流
        BufferedOutputStream bos =  new BufferedOutputStream(os);
        // 3.寫資料出去
        bos.write('a');
        bos.write(100);
        bos.write("我愛中國".getBytes());
        bos.close();
    }
}
           

位元組流性能

利用位元組流的複制統計各種寫法形式下緩沖流的性能執行情況

複制流:

  • 使用低級的位元組流按照一個一個位元組的形式複制檔案
  • 使用低級的位元組流按照一個一個位元組數組的形式複制檔案
  • 使用進階的緩沖位元組流按照一個一個位元組的形式複制檔案
  • 使用進階的緩沖位元組流按照一個一個位元組數組的形式複制檔案

進階的緩沖位元組流按照一個一個位元組數組的形式複制檔案,性能最高,建議使用

字元緩沖輸入

字元緩沖輸入流:BufferedReader

作用:字元緩沖輸入流把字元輸入流包裝成進階的緩沖字元輸入流,可以提高字元輸入流讀資料的性能。

構造器:public BufferedReader(Reader reader)

原理:緩沖字元輸入流預設會有一個 8K 的字元緩沖池,可以提高讀字元的性能

按照行讀取資料的功能:public String readLine() 讀取一行資料傳回,讀取完畢傳回 null

public static void main(String[] args) throws Exception {
    // 1.定義一個原始的字元輸入流讀取源檔案
    Reader fr = new FileReader("Demo/src/test.txt");
    // 2.把低級的字元輸入流管道包裝成一個進階的緩沖字元輸入流管道
    BufferedReader br = new BufferedReader(fr);
    // 定義一個字元串變量存儲每行資料
    String line;
    while((line = br.readLine()) != null){
        System.out.println(line);
    }
    br.close();
    //淘汰數組循環讀取
    //char[] buffer = new char[1024];
    //int len;
    //while((len = br.read(buffer)) != -1){
    //System.out.println(new String(buffer , 0 , len));
}
複制代碼           

字元緩沖輸出

符緩沖輸出流:BufferedWriter

作用:把低級的字元輸出流包裝成一個進階的緩沖字元輸出流,提高寫字元資料的性能。

構造器:public BufferedWriter(Writer writer)

原理:進階的字元緩沖輸出流多了一個 8K 的字元緩沖池,寫資料性能極大提高了

字元緩沖輸出流多了一個換行的特有功能:public void newLine() 建立一行

public static void main(String[] args) throws Exception {
    Writer fw = new FileWriter("Demo/src/test.txt",true);//追加
    BufferedWriter bw = new BufferedWriter(fw);
    
    bw.write("我愛學習Java");
    bw.newLine();//換行
    bw.close();
}
複制代碼           

高效原因

字元型緩沖流高效的原因:(空間換時間)

  • BufferedReader:每次調用 read 方法,隻有第一次從磁盤中讀取了 8192(8k)個字元,存儲到該類型對象的緩沖區數組中,将其中一個傳回給調用者,再次調用 read 方法時,就不需要通路磁盤,直接從緩沖區中拿出一個資料即可,提升了效率
  • BufferedWriter:每次調用 write 方法,不會直接将字元重新整理到檔案中,而是存儲到字元數組中,等字元數組寫滿了,才一次性重新整理到檔案中,減少了和磁盤互動的次數,提升了效率

位元組型緩沖流高效的原因:

  • BufferedInputStream:在該類型中準備了一個數組,存儲位元組資訊,當外界調用 read() 方法想擷取一個位元組的時候,該對象從檔案中一次性讀取了 8192 個位元組到數組中,隻傳回了第一個位元組給調用者。将來調用者再次調用 read 方法時,目前對象就不需要再次通路磁盤,隻需要從數組中取出一個位元組傳回給調用者即可,由于讀取的是數組,是以速度非常快。當 8192 個位元組全都讀取完成之後,再需要讀取一個位元組,就得讓該對象到檔案中讀取下一個 8192 個位元組
  • BufferedOutputStream:在該類型中準備了一個數組,存儲位元組資訊,當外界調用 write 方法想寫出一個位元組的時候,該對象直接将這個位元組存儲到了自己的數組中,而不重新整理到檔案中。一直到該數組所有 8192 個位置全都占滿,該對象才把這個數組中的所有資料一次性寫出到目标檔案中。如果最後一次循環沒有将數組寫滿,最終在關閉流對象的時候,也會将該數組中的資料重新整理到檔案中。

注意:位元組流和字元流,都是裝滿時自動寫出,或者沒滿時手動 flush 寫出,或 close 時重新整理寫出

轉換流

亂碼問題

字元流讀取:

代碼編碼            檔案編碼         中文情況。
UTF-8              UTF-8           不亂碼!
GBK                GBK             不亂碼!
UTF-8              GBK             亂碼!           
  • 如果代碼編碼和讀取的檔案編碼一緻,字元流讀取的時候不會亂碼
  • 如果代碼編碼和讀取的檔案編碼不一緻,字元流讀取的時候會亂碼

字元輸入

字元輸入轉換流:InputStreamReader

作用:解決字元流讀取不同編碼的亂碼問題,把原始的位元組流按照預設的編碼或指定的編碼轉換成字元輸入流

構造器:

  • public InputStreamReader(InputStream is):使用目前代碼預設編碼 UTF-8 轉換成字元流
  • public InputStreamReader(InputStream is, String charset):指定編碼把位元組流轉換成字元流
public class InputStreamReaderDemo{
    public static void main(String[] args) throws Exception {
        // 1.提取GBK檔案的原始位元組流
        InputStream is = new FileInputStream("D:\seazean\Netty.txt");
        // 2.把原始位元組輸入流通過轉換流,轉換成 字元輸入轉換流InputStreamReader
        InputStreamReader isr = new InputStreamReader(is, "GBK"); 
        // 3.包裝成緩沖流
        BufferedReader br = new BufferedReader(isr);
        //循環讀取
        String line;
        while((line = br.readLine()) != null){
            System.out.println(line);
        }
    }
}           

字元輸出

字元輸出轉換流:OutputStreamWriter

作用:可以指定編碼把位元組輸出流轉換成字元輸出流,可以指定寫出去的字元的編碼

構造器:

  • public OutputStreamWriter(OutputStream os):用預設編碼 UTF-8 把位元組輸出流轉換成字元輸出流
  • public OutputStreamWriter(OutputStream os, String charset):指定編碼把位元組輸出流轉換成
OutputStream os = new FileOutputStream("/usr/local");
OutputStreamWriter osw = new OutputStreamWriter(os,"GBK");
osw.write("測試i");   
osw.close();