BufferedInputStream.read() **方法簽名與 `InputStream.read()` 相同**,但**內部實現完全不同**。「緩衝」不在方法簽名體現,而在於**內部維護一個 byte[] 緩衝區 (默認 8192 字節)**。
public abstract int read() throws IOException;
子類 (如 `FileInputStream`) 每次調用**直接發起系統調用** 讀取 1 字節,極慢。
private byte[] buf; // 緩衝區
private int count; // 緩衝區有效字節數
private int pos; // 當前讀取位置
public synchronized int read() throws IOException {
if (pos >= count) { // 緩衝區耗盡
fill(); // 批量填充緩衝區
if (pos >= count) return -1;
}
return buf[pos++] & 0xFF; // 從緩衝區直接取字節 (極快,用戶態)
}
private void fill() throws IOException {
// 一次系統調用讀取大量數據到 buf
int n = getInIfOpen().read(buf, 0, buf.length);
if (n > 0) {
count = n;
pos = 0;
}
}
| 場景 | 系統調用次數 (讀 1MB) | 用戶態/內核態切換 | 相對耗時 |
|---|---|---|---|
| FileInputStream.read() | 1,048,576 次 (每字節 1 次) | 極多 | 基準 100% |
| BufferedInputStream.read() (8KB 緩衝) | 128 次 (1MB/8KB) | 極少 | **< 1%** |
| BufferedInputStream.read(byte[], off, len) | 1 次 (直接複製緩衝區) | 最少 | 最快 |
| 特性 | BufferedReader (字符流) | BufferedInputStream (字節流) |
|---|---|---|
| 讀取單位 | 字符 | 字節 |
| 核心方法 | readLine() (按行讀取) | read() / read(byte[]) |
| 解碼職責 | 內部包裝 `InputStreamReader` (字節→字符) | 無解碼,原始字節 |
| 適用場景 | 文本文件、配置文件、日志分析 | 二進制文件 (圖片、視頻、壓縮包)、網絡流 |