Java-IO流之緩沖流詳解

Java-IO流之緩沖流詳解

    • 一、緩沖流概述
      • 1.1 什么是緩沖流
      • 1.2 緩沖流的工作原理
      • 1.3 緩沖流的優勢
    • 二、字節緩沖流詳解
      • 2.1 BufferedInputStream
        • 2.1.1 構造函數
        • 2.1.2 核心方法
        • 2.1.3 使用示例
      • 2.2 BufferedOutputStream
        • 2.2.1 構造函數
        • 2.2.2 核心方法
        • 2.2.3 使用示例
    • 三、字符緩沖流詳解
      • 3.1 BufferedReader
        • 3.1.1 構造函數
        • 3.1.2 核心方法
        • 3.1.3 使用示例
      • 3.2 BufferedWriter
        • 3.2.1 構造函數
        • 3.2.2 核心方法
        • 3.2.3 使用示例
    • 四、緩沖流的性能優化
      • 4.1 緩沖區大小選擇
      • 4.2 與其他流結合使用
      • 4.3 批量讀寫操作
    • 五、緩沖流的最佳實踐
      • 5.1 使用try-with-resources語句
      • 5.2 合理選擇緩沖區大小
      • 5.3 及時刷新緩沖區
    • 六、常見問題與解決方案
      • 6.1 緩沖區未刷新導致數據丟失
      • 6.2 緩沖流與mark/reset操作
      • 6.3 緩沖流性能問題

Java 中常見的輸入輸出(IO)操作,直接操作原始的字節流或字符流往往效率低下,尤其是處理大量數據時。Java IO體系中的緩沖流(Buffered Stream)通過引入緩沖區機制,顯著提高了IO操作的性能。本文我將深入探討Java緩沖流的原理、使用方法及性能優化技巧,幫你全面掌握這一重要技術。

一、緩沖流概述

1.1 什么是緩沖流

緩沖流是Java IO體系中用于裝飾其他流的特殊流,它通過在內存中設置緩沖區,減少了直接與底層數據源(如磁盤、網絡)的交互次數,從而提高了IO操作的效率。Java提供了四種緩沖流:

  • BufferedInputStream:字節輸入緩沖流
  • BufferedOutputStream:字節輸出緩沖流
  • BufferedReader:字符輸入緩沖流
  • BufferedWriter:字符輸出緩沖流

1.2 緩沖流的工作原理

緩沖流的核心是內部維護的一個緩沖區數組:

  • 輸入緩沖流:從數據源讀取數據時,先將數據批量讀入緩沖區,后續的讀取操作直接從緩沖區獲取數據,減少了與數據源的交互次數。
  • 輸出緩沖流:向目標寫入數據時,先將數據寫入緩沖區,當緩沖區滿或調用flush()方法時,再將緩沖區中的數據批量寫入目標,減少了與目標的交互次數。

1.3 緩沖流的優勢

  • 提高IO性能:減少了與底層數據源的交互次數
  • 簡化編程模型:提供了更方便的API,如BufferedReader的readLine()方法
  • 支持mark和reset操作:某些緩沖流支持標記和重置操作,增強了靈活性

二、字節緩沖流詳解

2.1 BufferedInputStream

BufferedInputStream為字節輸入流提供緩沖功能,繼承自FilterInputStream

2.1.1 構造函數
  • BufferedInputStream(InputStream in):使用默認緩沖區大小(8192字節)創建緩沖流
  • BufferedInputStream(InputStream in, int size):使用指定大小的緩沖區創建緩沖流
2.1.2 核心方法
  • int read():從緩沖流讀取一個字節
  • int read(byte[] b, int off, int len):從緩沖流讀取字節到數組的指定位置
  • void close():關閉流并釋放資源
  • void mark(int readlimit):標記當前位置
  • void reset():重置到最后標記的位置
2.1.3 使用示例
import java.io.*;public class BufferedInputStreamExample {public static void main(String[] args) {try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("large_file.dat"), 16384)) {byte[] buffer = new byte[4096];int bytesRead;while ((bytesRead = bis.read(buffer)) != -1) {// 處理讀取的數據processData(buffer, bytesRead);}} catch (IOException e) {e.printStackTrace();}}private static void processData(byte[] buffer, int bytesRead) {// 數據處理邏輯}
}

2.2 BufferedOutputStream

BufferedOutputStream為字節輸出流提供緩沖功能,繼承自FilterOutputStream

2.2.1 構造函數
  • BufferedOutputStream(OutputStream out):使用默認緩沖區大小(8192字節)創建緩沖流
  • BufferedOutputStream(OutputStream out, int size):使用指定大小的緩沖區創建緩沖流
2.2.2 核心方法
  • void write(int b):向緩沖流寫入一個字節
  • void write(byte[] b, int off, int len):向緩沖流寫入字節數組的指定部分
  • void flush():刷新緩沖區,將數據寫入底層輸出流
  • void close():關閉流,關閉前會先刷新緩沖區
2.2.3 使用示例
import java.io.*;public class BufferedOutputStreamExample {public static void main(String[] args) {try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("output.dat"), 16384)) {byte[] data = generateData(1024 * 1024); // 生成1MB數據// 寫入數據到緩沖區bos.write(data);// 確保所有數據都寫入底層流bos.flush();} catch (IOException e) {e.printStackTrace();}}private static byte[] generateData(int size) {byte[] data = new byte[size];// 填充數據for (int i = 0; i < size; i++) {data[i] = (byte) (i % 256);}return data;}
}

三、字符緩沖流詳解

3.1 BufferedReader

BufferedReader為字符輸入流提供緩沖功能,并提供了讀取整行的便捷方法。

3.1.1 構造函數
  • BufferedReader(Reader in):使用默認緩沖區大小(8192字符)創建緩沖流
  • BufferedReader(Reader in, int sz):使用指定大小的緩沖區創建緩沖流
3.1.2 核心方法
  • int read():讀取單個字符
  • int read(char[] cbuf, int off, int len):讀取字符到數組的指定位置
  • String readLine():讀取一行文本,以換行符結束
  • void close():關閉流并釋放資源
3.1.3 使用示例
import java.io.*;public class BufferedReaderExample {public static void main(String[] args) {try (BufferedReader reader = new BufferedReader(new FileReader("large_text_file.txt"), 32768)) {String line;while ((line = reader.readLine()) != null) {// 處理每行文本processLine(line);}} catch (IOException e) {e.printStackTrace();}}private static void processLine(String line) {// 處理文本行的邏輯}
}

3.2 BufferedWriter

BufferedWriter為字符輸出流提供緩沖功能,并提供了寫入換行符的便捷方法。

3.2.1 構造函數
  • BufferedWriter(Writer out):使用默認緩沖區大小(8192字符)創建緩沖流
  • BufferedWriter(Writer out, int sz):使用指定大小的緩沖區創建緩沖流
3.2.2 核心方法
  • void write(int c):寫入單個字符
  • void write(char[] cbuf, int off, int len):寫入字符數組的指定部分
  • void write(String s, int off, int len):寫入字符串的指定部分
  • void newLine():寫入一個行分隔符
  • void flush():刷新緩沖區
  • void close():關閉流,關閉前會先刷新緩沖區
3.2.3 使用示例
import java.io.*;public class BufferedWriterExample {public static void main(String[] args) {try (BufferedWriter writer = new BufferedWriter(new FileWriter("output.txt"), 32768)) {for (int i = 0; i < 100000; i++) {writer.write("這是第" + i + "行文本");writer.newLine(); // 寫入換行符}// 確保所有數據都寫入文件writer.flush();} catch (IOException e) {e.printStackTrace();}}
}

四、緩沖流的性能優化

4.1 緩沖區大小選擇

緩沖區大小對性能有顯著影響,一般來說:

  • 較大的緩沖區(如32KB或64KB)適合處理大文件或網絡數據
  • 較小的緩沖區(如4KB或8KB)適合處理小文件或頻繁的IO操作
  • 默認緩沖區大小(8KB)通常適用于大多數場景

性能測試示例

import java.io.*;public class BufferSizePerformanceTest {private static final int FILE_SIZE = 1024 * 1024 * 100; // 100MBprivate static final String TEST_FILE = "test_file.dat";public static void main(String[] args) {generateTestFile();int[] bufferSizes = {4096, 8192, 16384, 32768, 65536};for (int size : bufferSizes) {testReadPerformance(size);}}private static void generateTestFile() {try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(TEST_FILE))) {byte[] buffer = new byte[1024];for (int i = 0; i < FILE_SIZE / 1024; i++) {bos.write(buffer);}} catch (IOException e) {e.printStackTrace();}}private static void testReadPerformance(int bufferSize) {long startTime = System.currentTimeMillis();try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(TEST_FILE), bufferSize)) {byte[] buffer = new byte[1024];while (bis.read(buffer) != -1) {// 讀取但不處理數據}} catch (IOException e) {e.printStackTrace();}long endTime = System.currentTimeMillis();System.out.println("緩沖區大小: " + bufferSize + " 字節, 讀取時間: " + (endTime - startTime) + " 毫秒");}
}

4.2 與其他流結合使用

緩沖流通常與其他流組合使用,形成功能強大的流管道:

示例:讀取壓縮文件中的文本

import java.io.*;
import java.util.zip.GZIPInputStream;public class CombinedStreamExample {public static void main(String[] args) {try (BufferedReader reader = new BufferedReader(new InputStreamReader(new GZIPInputStream(new FileInputStream("data.txt.gz"))))) {String line;while ((line = reader.readLine()) != null) {System.out.println(line);}} catch (IOException e) {e.printStackTrace();}}
}

4.3 批量讀寫操作

使用數組進行批量讀寫比單字節/字符讀寫效率更高:

高效寫法

try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("input.dat"))) {byte[] buffer = new byte[8192];int bytesRead;while ((bytesRead = bis.read(buffer)) != -1) {// 批量處理數據}
}

低效寫法

try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("input.dat"))) {int byteValue;while ((byteValue = bis.read()) != -1) {// 單字節處理數據}
}

五、緩沖流的最佳實踐

5.1 使用try-with-resources語句

確保流資源被正確關閉,避免資源泄漏:

try (BufferedReader reader = new BufferedReader(new FileReader("input.txt"));BufferedWriter writer = new BufferedWriter(new FileWriter("output.txt"))) {String line;while ((line = reader.readLine()) != null) {writer.write(processLine(line));writer.newLine();}
} catch (IOException e) {e.printStackTrace();
}

5.2 合理選擇緩沖區大小

根據實際應用場景選擇合適的緩沖區大小,避免過大或過小:

// 處理大文件時使用較大的緩沖區
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("large_file.dat"), 65536)) {// 處理數據
}

5.3 及時刷新緩沖區

在需要確保數據寫入目標時,調用flush()方法:

try (BufferedWriter writer = new BufferedWriter(new FileWriter("log.txt"))) {// 寫入重要日志writer.write("系統啟動成功");writer.newLine();// 立即刷新,確保數據寫入文件writer.flush();// 繼續寫入其他日志writer.write("開始處理數據");writer.newLine();
}

六、常見問題與解決方案

6.1 緩沖區未刷新導致數據丟失

如果在關閉流之前沒有調用flush()方法,緩沖區中的數據可能不會被寫入目標。使用try-with-resources語句可以避免這個問題,因為它會自動調用close()方法,而close()方法會先刷新緩沖區。

6.2 緩沖流與mark/reset操作

某些緩沖流支持mark和reset操作,但需要注意:

  • 標記位置不能超過緩沖區大小
  • 調用reset()后,只能讀取到標記位置之后、緩沖區范圍內的數據

示例

try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("data.dat"))) {// 標記當前位置bis.mark(1024);// 讀取一些數據byte[] buffer = new byte[512];bis.read(buffer);// 重置到標記位置bis.reset();// 可以再次讀取之前的數據bis.read(buffer);
}

6.3 緩沖流性能問題

  • 如果發現使用緩沖流后性能反而下降,可能是因為:
    • 緩沖區設置過小,導致頻繁刷新
    • 每次只讀寫少量數據,沒有充分利用緩沖區
    • 底層IO設備本身速度很快,緩沖帶來的收益有限

若這篇內容幫到你,動動手指支持下!關注不迷路,干貨持續輸出!
ヾ(′? ˋ)ノヾ(′? ˋ)ノヾ(′? ˋ)ノヾ(′? ˋ)ノヾ(′? ˋ)ノ

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/85867.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/85867.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/85867.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

健康檢查:在 .NET 微服務模板中優雅配置 Health Checks

&#x1f680; 健康檢查&#xff1a;在 .NET 微服務模板中優雅配置 Health Checks &#x1f4da; 目錄 &#x1f680; 健康檢查&#xff1a;在 .NET 微服務模板中優雅配置 Health Checks一、背景與意義 &#x1f50d;二、核心配置 &#x1f527;2.1 引入必要的 NuGet 依賴 &…

關于akka官方quickstart示例程序(scala)的記錄

參考資料 https://doc.akka.io/libraries/akka-core/current/typed/actors.html#first-example 關于scala語法的注意事項 extends App是個語法糖&#xff0c;等同于直接在伴生對象中編寫main 方法對象是通過apply方法創建的&#xff0c;也可以通過對象的名稱單獨創建&#x…

基于vue3-elemenyui的頁面加載及新建瀏覽頁案例

1.參考鏈接&#xff1a; 基于創建vue3鏈接&#xff1a;Vue3前端項目創建_vscode創建vue3項目-CSDN博客 基于創建elementui鏈接&#xff1a;Vue3引入ElementPlus_vue引入element-plus-CSDN博客 2.案例內容 該案例實現了基本的app.vue的路由跳轉、新建瀏覽頁參數傳入以及瀏覽…

板凳-------Mysql cookbook學習 (十)

5.6 改變字符串的字符集或字符排序 mysql> set s1 my string; Query OK, 0 rows affected (0.01 sec)mysql> set s2 convert(s1 using utf8); Query OK, 0 rows affected, 1 warning (0.00 sec)mysql> select charset(s1), charset(s2); -------------------------…

使用nginx配置反向代理,負載均衡

首先啥叫反向代理 咋配置呢&#xff0c;那當然是在nginx目錄下改conf文件了 具體咋改呢&#xff0c;那就新增一個新的server配置&#xff0c;然后在location里新增你想代理的服務器 實際上負載均衡也就是根據反向代理的思路來的&#xff0c;如下所示 配置的話實際上也與上…

嵌入式開發之STM32學習筆記day20

STM32F103C8T6 PWR電源控制 1 PWR簡介 PWR&#xff08;Power Control&#xff09;電源控制單元是STM32微控制器中一個重要的組成部分&#xff0c;它負責管理系統的電源管理功能&#xff0c;以優化功耗并提高效率。PWR負責管理STM32內部的電源供電部分&#xff0c;可以實現可編…

Spring AI(10)——STUDIO傳輸的MCP服務端

Spring AI MCP&#xff08;模型上下文協議&#xff09;服務器Starters提供了在 Spring Boot 應用程序中設置 MCP 服務器的自動配置。它支持將 MCP 服務器功能與 Spring Boot 的自動配置系統無縫集成。 本文主要演示支持STDIO傳輸的MCP服務器 僅支持STDIO傳輸的MCP服務器 導入j…

Java八股文——集合「Set篇」

Set集合有什么特點&#xff1f;如何實現key無重復的&#xff1f; 面試官您好&#xff0c;Set 集合是 Java 集合框架中的一個重要接口&#xff0c;它繼承自 Collection 接口&#xff0c;其最顯著的特點和設計目標就是存儲一組不重復的元素。 一、Set集合的主要特點&#xff1a…

「數據分析 - NumPy 函數與方法全集」【數據分析全棧攻略:爬蟲+處理+可視化+報告】

- 第 104 篇 - Date: 2025 - 06 - 05 Author: 鄭龍浩/仟墨 NumPy 函數與方法全集 文章目錄 NumPy 函數與方法全集1. 數組創建與初始化基礎創建序列生成特殊數組 2. 數組操作形狀操作合并與分割 3. 數學運算基礎運算統計運算 4. 隨機數生成基礎隨機分布函數 5. 文件IO文件讀寫 …

報表/報告組件(二)-實例與實現解釋

上篇《報表/報告組件(一)-指標/屬性組件設計》介紹了組件核心指標/屬性設計&#xff0c;本文以實例介紹各個特性的實現和效果&#xff0c;實例是多個報告融合&#xff0c;顯示所有的特性。 設計 指標/屬性組件是報告/報表關鍵部分&#xff0c;上篇已介紹過&#xff0c;本節回顧…

Flutter嵌入式開發實戰 ——從樹莓派到智能家居控制面板,打造工業級交互終端

一、為何選擇Flutter開發嵌入式設備&#xff1f; 1. 跨平臺能力降維打擊 特性傳統方案Flutter方案開發效率需分別開發Android/Linux一套代碼多端部署內存占用200MB (QtWeb引擎)<80MB (Release模式)熱重載支持不支持支持 2. 工業級硬件支持實測 樹莓派4B&#xff1a;1080…

[藍橋杯]機器人塔

題目描述 X 星球的機器人表演拉拉隊有兩種服裝&#xff0c;A 和 B。 他們這次表演的是搭機器人塔。 類似&#xff1a; A B B A B A A A B B B B B A B A B A B B A 隊內的組塔規則是&#xff1a; A 只能站在 AA 或 BB 的肩上。 B 只能站在 AB 或 BA 的肩上。 你的…

語雀文檔保存失敗URI malformed

原因 原因未知&#xff0c;我用deekseek將回答的答案復制到語雀文檔時出現了這個異常&#xff0c;在知識庫里面一直保存失敗 語雀文檔保存失敗URI malformed 解決方案 使用小記&#xff0c;將里面的內容轉移到小記里&#xff0c;將小記移到知識庫中即可

小明的Java面試奇遇之互聯網保險系統架構與性能優化

一、文章標題 小明的Java面試奇遇之互聯網保險系統架構與性能優化&#x1f680; 二、文章標簽 Java,Spring Boot,MyBatis,Redis,Kafka,JVM,多線程,互聯網保險,系統架構,性能優化 三、文章概述 本文模擬了程序員小明在應聘互聯網保險系統開發崗位時&#xff0c;參與的一場深…

從零開始的嵌入式學習day33

網絡編程及相關概念 UDP網絡通信程序 UDP網絡通信操作 一、網絡編程及相關概念 1. 網絡編程概念&#xff1a; 指通過計算機網絡實現程序間通信的技術&#xff0c;涉及協議、套接字、數據傳輸等核心概念。常見的應用場景包括客戶端-服務器模型、分布式系統、實時通信等。…

Kotlin 1. 搭建Kotlin開發環境

本實戰概述旨在指導用戶搭建Kotlin開發環境&#xff0c;并進行簡單的編程實踐。首先&#xff0c;用戶需安裝IntelliJ IDEA&#xff0c;并進行基本設置&#xff0c;如選擇主題、調整字體和安裝插件等。接著&#xff0c;創建Kotlin項目&#xff0c;設置項目名稱、位置和JDK版本&a…

Mysql的B-樹和B+樹的區別總結

B 樹也稱 B- 樹&#xff0c;全稱為 多路平衡查找樹&#xff0c;B 樹是 B 樹的一種變體。B 樹和 B 樹中的 B 是 Balanced&#xff08;平衡&#xff09;的意思。 目前大部分數據庫系統及文件系統都采用 B-Tree 或其變種 BTree 作為索引結構。 B 樹& B 樹兩者有何異同呢&…

COMSOL學習筆記-靜電場仿真

最近在學習COMSOL&#xff0c;做了一個靜電場仿真的例子&#xff0c;分享一下。 參考了下面的官方案例 計算電容 電容式位置傳感器的邊界元建模 三維模型 首先對靜電測試儀進行三維建模。 Comsol靜電場仿真 使用comsol進行靜電場仿真&#xff0c;控制方程為泊松方程&#…

JavaScript 循環方法對比指南

JavaScript 循環方法對比指南 1. 標準 for 循環 語法&#xff1a; for (let i 0; i < arr.length; i) {console.log(arr[i]); }優點 ? 完全控制索引&#xff0c;適合需要精確控制遍歷順序或步長的場景。 ? 性能最優&#xff0c;在超大規模數據遍歷時比高階方法&#x…

【快餐點餐簡易軟件】佳易王快餐店點餐系統軟件功能及操作教程

一、軟件概述與核心優勢 &#xff08;一&#xff09;試用版獲取方式 資源下載路徑&#xff1a;進入博主頭像主頁第一篇文章末尾&#xff0c;點擊卡片按鈕&#xff1b;或訪問左上角博客主頁&#xff0c;通過右側按鈕獲取詳細資料。 說明&#xff1a;下載文件為壓縮包&#xff…