首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java IO 進階:深入解析 BufferedInputStream 緩衝輸入流原理與實戰

     編輯:Java 相關知識

BufferedInputStream 核心概念

BufferedInputStream 是 Java IO 體系中用於提升讀取效率的緩衝輸入流,它繼承自 FilterInputStream,通過內部維護一個字節數組緩衝區(默認 8192 字節),將底層輸入流的數據分批讀入內存,後續的 read() 操作直接從緩衝區獲取數據,避免頻繁訪問磁盤或網絡,顯著提高 I/O 性能。此外,它還支持 mark() 和 reset() 標記重置功能,便於在流中回退。

核心源碼解析(基於 JDK 1.7)

關鍵字段

private static int defaultBufferSize = 8192; // 默認緩衝區大小
protected volatile byte buf[];               // 緩衝區數組
protected int count;                         // 緩衝區中有效數據的字節數
protected int pos;                           // 當前讀取位置索引
protected int markpos = -1;                  // 標記位置,-1 表示無標記
protected int marklimit;                     // 標記最大限制

其中 buf 配合 AtomicReferenceFieldUpdater 實現多線程下的原子性更新。

核心方法:fill()

fill() 是填充緩衝區的關鍵邏輯,根據標記狀態和緩衝區剩餘空間分為五種情況處理:

  1. 無標記且緩衝區讀完:直接將 pos 歸零,從底層流讀取新數據填滿緩衝區。
  2. 有標記(markpos > 0)且緩衝區已滿:通過 System.arraycopy 保留標記位置到末尾的數據移至緩衝區頭部,騰出空間繼續讀取。
  3. 標記在開頭(markpos = 0)且緩衝區長度 ≥ marklimit:取消標記(markpos = -1),重置 pos = 0,丟棄舊數據重新讀取。
  4. 標記在開頭且緩衝區長度 < marklimit:擴容緩衝區(雙倍或至 marklimit),複製舊數據,再讀取新數據。
  5. 其他情況:直接從當前 pos 開始讀取補充數據。

這種設計兼顧了標記回退需求與內存佔用控制,marklimit 防止無限擴容導致 OOM。

實戰示例

public class BufferedInputStreamDemo {
    public static void main(String[] args) {
        File file = new File("bufferedinputstream.txt");
        try (BufferedInputStream bis = new BufferedInputStream(
                new FileInputStream(file), 512)) {
            
            // 讀取前 5 個字節
            for (int i = 0; i < 5; i++) {
                if (bis.available() >= 0) {
                    int b = bis.read();
                    System.out.printf("%d : 0x%s%n", i, Integer.toHexString(b));
                }
            }
            
            // 標記當前位置(第 6 個字節),marklimit 1024
            bis.mark(1024);
            bis.skip(22); // 跳過 22 字節
            
            byte[] buf = new byte[5];
            bis.read(buf, 0, 5);
            System.out.println("str1=" + new String(buf)); // 輸出 01234
            
            bis.reset(); // 回退到標記處
            bis.read(buf, 0, 5);
            System.out.println("str2=" + new String(buf)); // 輸出 fghij
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

測試文件內容:abcdefghijklmnopqrstuvwxyz\n0123456789\nABCDEFGHIJKLMNOPQRSTUVWXYZ

輸出結果驗證了標記/重置機制:先讀 a~e,標記 f,跳過後讀 0~4,重置後讀 f~j。

總結

BufferedInputStream 通過緩衝區減少物理讀取次數,配合 mark/reset 提供隨機訪問能力,是處理大文件、網絡流的首選裝飾器。理解 fill() 的五種分支邏輯,有助於排查緩衝區滿、標記失效等邊界問題。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved