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

Java 緩衝流 BufferedInputStream 與 BufferedOutputStream 完整 API 解析與實戰範例

     編輯:Java 相關知識

前言:為什麼需要緩衝流?

直接操作檔案或網路流讀寫單一位元組極度低效。BufferedInputStream / BufferedOutputStream 透過內部緩衝區陣列(預設 8KB),將「多次小量讀寫」合併為「少量大量讀寫」,大幅減少系統呼叫次數,是 Java I/O 效能優化的基石。本文將系統整理兩大緩衝流的核心 API、關鍵特性(mark/reset、flush 機制),並附上可直接執行的完整測試程式碼。


一、BufferedInputStream:讀取端的加速器

核心特性

  • 繼承 FilterInputStream,裝飾者模式包裝底層 InputStream
  • 內部維護 byte[] buf 緩衝區,支援 mark(int readlimit) / reset() 標記回滾
  • 建構子可指定緩衝區大小:new BufferedInputStream(in, 512)

關鍵 API 速查

方法說明
read()讀取單一位元組,自動從緩衝區取值,緩衝區耗盡時自動填充
read(byte[] b, int off, int len)批次讀取至陣列,效能最佳
available()返回可不阻塞讀取的位元組數(含緩衝區剩餘)
mark(int readlimit)標記當前位置,readlimit 為允許讀取上限前仍能 reset
reset()回到 mark 位置,配合 markSupported() 檢查支援性
skip(long n)跳過 n 個位元組,內部優化可直接移動指標

完整測試程式碼:mark/reset/skip 實戰

import java.io.*; public class BufferedInputStreamDemo { private static final int LEN = 5; public static void main(String[] args) { test(); } private static void test() { try (BufferedInputStream bis = new BufferedInputStream( new FileInputStream("bufferedinputstream.txt"), 512)) { // 1. 讀前 5 字節:a b c d e (0x61~0x65) for (int i = 0; i < LEN; i++) { if (bis.available() >= 0) { int b = bis.read(); System.out.printf("%d : 0x%s%n", i, Integer.toHexString(b)); } } // 2. 標記第 6 字節位置 (f) bis.mark(1024); // 3. 跳過 22 字節,指標來到 '0' bis.skip(22); // 4. 讀 5 字節 → "01234" byte[] buf = new byte[LEN]; bis.read(buf, 0, LEN); System.out.println("str1=" + new String(buf)); // 5. 重置回 mark 位置 (f) bis.reset(); // 6. 再讀 5 字節 → "fghij" bis.read(buf, 0, LEN); System.out.println("str2=" + new String(buf)); } catch (IOException e) { e.printStackTrace(); } } }

測試檔案內容

abcdefghijklmnopqrstuvwxyz 0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ

執行輸出

0 : 0x61 1 : 0x62 2 : 0x63 3 : 0x64 4 : 0x65 str1=01234 str2=fghij

二、BufferedOutputStream:寫入端的批次處理器

核心特性

  • 繼承 FilterOutputStream,包裝底層 OutputStream
  • 資料先寫入記憶體緩衝區,滿或 flush() / close() 才真正寫入底層
  • 建構子指定緩衝區大小:new BufferedOutputStream(out, 16)

關鍵 API

方法說明
write(int b)寫入單一位元組到緩衝區
write(byte[] b, int off, int len)批次寫入,效能最佳
flush()強制將緩衝區內容推送到底層流
close()自動 flush 後關閉底層流

三大場景實測:緩衝區大小 vs flush vs close

測試程式碼核心邏輯:建立 16 字節緩衝區,寫入 10/20 字節,觀察檔案實際落盤時機。

public class BufferedOutputStreamDemo { private static final byte[] LETTERS = "abcdefghijklmnopqrstuvwxyz".getBytes(); public static void main(String[] args) { test(10, false); // 場景 1 test(10, true); // 場景 2 + flush test(20, false); // 場景 3 寫入超過緩衝區 } private static void test(int writeCount, boolean manualFlush) { File file = new File("out.txt"); if (file.exists()) file.delete(); try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file), 16)) { bos.write(LETTERS, 0, writeCount); bos.write('\n'); if (manualFlush) bos.flush(); // 手動 flush // 此處模擬使用者輸入等待,觀察檔案內容 Thread.sleep(2000); } catch (Exception e) { e.printStackTrace(); } } }

場景結果對照

場景寫入量手動 flush等待期間檔案內容close 後檔案內容原理解析
110 字節否空abcdefghij\n未滿緩衝區(16),資料留在記憶體,close 時才 flush
210 字節是abcdefghij\nabcdefghij\nflush() 強制推送,資料即時落盤
320 字節否abcdefghijklmnopqrstabcdefghijklmnopqrst\n超過緩衝區直接繞過緩衝寫入底層,close 再寫入換行

三、效能優化黃金法則

  1. 優先使用批次讀寫:read(byte[]) / write(byte[]),避免單位元組操作。
  2. 合理設定緩衝區大小:檔案 I/O 建議 4KB~64KB(磁碟區塊大小倍數);網路 I/O 視 MTU 調整。
  3. 關鍵節點主動 flush:網路傳輸、進程間通訊、日誌寫入等需即時可見時,呼叫 flush()。
  4. try-with-resources 確保 close:JDK 7+ 自動處理資源釋放與最終 flush。

總結

BufferedInputStream 賦予「標記回滾」隨機存取能力,BufferedOutputStream 提供「批次寫入」吞吐優勢。掌握緩衝區滿溢、flush、close 三者觸發落盤的精確時機,是寫出高效、正確 I/O 程式的關鍵。建議在專案中封裝通用的 IOUtils.copyLarge(in, out, bufferSize) 工具方法,統一緩衝策略,避免重複造輪子。

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