6.緩衝字節輸入流BufferedInputStream

6.BufferedInputStream 緩衝輸入字節流

1.BufferedInputStream:

       通過使用FileInputStream我們可以知道,使用緩衝數組能提高讀取效率。因此sun給我們提供了一個緩衝輸入字節流對象,讓我們可以更高效的讀取文件。

2.輸入字節流體系

- - - - | InputStream 輸入字節流的基類,抽象類

- - - - - - - - - | FileInputStream 讀取文件數據的輸入字節流(直接從硬盤讀取),每次讀取一個字節

- - - - - - - - - | BufferedInputStream 緩衝輸入字節流,它的出現主要是爲了提高讀取文件數據的效率。其實BufferedInputStream只不過是在內部維護了一個8192字節(8kb)的字節數組而已。

 

3.使用BufferedInputStream的步驟:

   1.找到目標文件

      File file = new File("E:\\aa\\a.txt");

   2.建立數據通道

      BufferedInputStream bufferedInputStream = new BufferedInputStream(newFileInputStream(file));

   3.讀取數據

      int content = bufferedInputStream.read();// 借用的是FileInputStream的read()方法的讀取文件數據的能力,所有緩衝字節流都不具備讀寫文件的功能。

   4.釋放流資源

      bufferedInputStream.close();// (實際上關閉的是 FileInputStream的資源。)

 

4.關於 BufferedInputStream 的問題:

(1)爲什麼創建BufferedInputStream對象的時候,要傳入FileInputStream對象?

   答:因爲所有的緩衝字節流都不具備讀寫文件的能力。所以BufferedInputStream不具備讀寫文件的能力,不能直接從硬盤中讀取文件中的數據。需要藉助FileInputStream的read()的讀取文件數據的能力來完成文件數據的讀取操作。

 

(2)BufferedInputStream出現的目的是爲了提高讀取數據的效率,但是BufferedInputStream每次讀取一個字節的數據,而FileInputStream也是每次讀寫一個字節的數據,那麼BufferedInputStream的高效率從何而來呢?

   答:BufferedInputStream只不過是在類的內部維護了一個8192字節(8kb)的字節數組而已。

      從BufferedInputStream的源碼看它的運行原理:

BufferedInputStream的源碼:

public synchronized int read() throws IOException {

   if (pos >= count) {

      fill();

      if (pos >= count)

         return -1;

   }

   return getBufIfOpen()[pos++] & 0xff;

}

 

源碼解讀:

pos:當前已經讀取到了第幾個字節(指針作用)

count:本次讀取了幾個字節存儲到了緩衝數組中。

getBufIfOpen():獲取字節數組中的數據。

fill():填充。獲取getBufIfOpen()獲取到的字節數組中的數據。使用BufferedInputStream內部維護的數組去讀取文件數據,每次最多讀取8kb(8192字節)的數據進入緩衝數組。

 

通過源碼可以得知BufferedInputStream緩衝字節輸入流的運行原理:

   BufferedInputStream 是從字節數組(也就是內存中)讀取數據的,它沒有讀寫文件的能力。

    第一次讀取時pos和count都是0,此時進入if內部調用 fill() 方法,fill() 維護了 getBufIfOpen() 方法讀取的數據(每次最多8kb)。

    fill() 方法起到一個指針的作用,每讀取完一個字節指針索引值+1,直到pos>=count,return -1讀取完字節數組中的所有數據,然後pos指針清零,繼續下一輪的讀取操作,直到將文件中的所有數據都讀取完成。

 

(3)當使用完流資源,要第一時間將流資源關閉,爲什麼只關閉BufferedInputStream的流資源,而不關閉FileInputStream的流資源?

   答:關閉BufferedInputStream的資源,實際上關閉的就是FileInputStream的資源,因爲BufferedInputStream不具備讀取文件的能力,所以不需要釋放資源。而它讀取文件的能力是藉助的FileInputStream的read()方法,所以關閉的實際上是FIleInputStream的資源。

5.BufferedInputStream與FileInputStream的使用選取問題?

看個人習慣,總的來說,使用FileInputStream搭配數組的效率應該比BufferedInputStream的效率要高。

從以下幾點可以分析出:

   1.執行流程:從BufferedInputStream的源碼可以看出,每次讀取字節都需要進行if判斷,這就很影響工作效率了。

   2.程序員所需寫的代碼量:兩種字節輸入流使用時,所需的代碼量是相同的。只不過FileInputStream需要自己去維護一個byte數組而BufferedInputStream卻需要將FileInputStream傳入它構建的對象中。

   3.維護數組:BufferedInputStream內部維護的數組是8kb(8192個字節),也就是1024*8個字節,是固定的。而程序員自己去維護數組的話,會更加靈活。

6.案例

public class Dome1 {
    /*
        3.使用BufferedInputStream的步驟:
            1.找到目標文件
            2.建立數據通道
            3.讀取數據
            4.釋放流資源
     */
    public static void main(String[] args) {
        // 1.找到目標文件
        File file = new File("E:\\aa\\bb\\a.txt");
        FileInputStream fileInputStream = null;
        BufferedInputStream bufferedInputStream = null;

        try {
            // 2.搭建數據通道
            // 疑問1:問什麼在創建BufferedInputStream的時候,要傳入FileInputStream? 因爲BufferedInputStream(所有緩衝字節流)不具備讀寫文件的能力,需要藉助FileInputStream的read()方法讀取文件數據內容。
            fileInputStream = new FileInputStream(file);
            bufferedInputStream = new BufferedInputStream(fileInputStream);

            // 3.讀取數據
            /*
                緩衝字節輸入流的運行原理:BufferedInputStream只不過是在類的內部維護了一個8192字節(8kb)的字節數組而已。
                BufferedInputStream源碼:
                    public synchronized int read() throws IOException {
                        if (pos >= count) {
                            fill();
                            if (pos >= count)
                                return -1;
                        }
                        return getBufIfOpen()[pos++] & 0xff;
                    }
                    pos:當前已經讀取到了第幾個字節(指針作用)
                    count:本次讀取了幾個字節存儲到了緩衝數組中。
                    getBufIfOpen():獲取字節數組中的數據。
                    fill():填充。獲取getBufIfOpen()獲取到的字節數組中的數據。使用BufferedInputStream內部維護的數組去讀取文件數據,每次最多讀取8kb(8192字節)的數據進入緩衝數組。

                通過源碼可以得知BufferedInputStream緩衝字節輸入流的運行原理:
                    BufferedInputStream是從字節數組(也就是內存中)讀取數據的,
                    第一次讀取時pos和count都是0,此時進入if內部調用fill()方法,fill()維護getBufIfOpen()方法一次性讀取的最多8kb的數據。
                    fill()方法起到一個指針的作用,每讀取完一個字節指針索引值+1,直到pos>=count,return -1讀取完文件中的所有數據。
             */
            int content = 0;
            while ((content = bufferedInputStream.read()) != -1) {
                System.out.println((char) content);
            }
        } catch (FileNotFoundException e) {
            System.out.println("尋找目標文件失敗...");
            throw new RuntimeException(e);// 將異常封裝到運行時異常處理掉
        } catch (IOException e) {
            System.out.println("讀取文件內容失敗...");
            throw new RuntimeException(e);
        } finally {
            try {
                // 4.釋放資源
                System.out.println("關閉流資源成功......");
                bufferedInputStream.close();//實際上釋放的是FileInputStream的資源,因爲BufferedInputStream不具備讀寫文件的能力,所以不能搭建與文件之間的通道,它藉助的是FileInputStream的read()方法來讀寫文件的數據。
            } catch (IOException e) {
                System.out.println("關閉流資源失敗......");
                throw new RuntimeException(e);
            }
        }
    }
}

總結:簡單來說,BufferedInputStream讀取文件的過程,是通過FileInputStream的read()方法,將硬盤中文件的數據內容讀取到BufferedInputStream內部維護的字節數組中,此時數據存儲到了內存中,BufferedInputStream的read()方法是從字節數組(也就是內存中)來讀取數據的。這也就是爲什麼BufferedInputStream明明不具備讀寫文件的功能,卻能讀取文件中數據的原因。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章