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

Java IO 文件讀取完全指南:FileInputStream/FileReader 兩種讀取姿勢與效能優化

     編輯:Java 相關知識

輸入流核心三步曲

  1. 建立流:new FileInputStream("path") 連接檔案。
  2. 讀取數據:調用 read() 從流拉取資料到記憶體。
  3. 關閉流:close() 釋放檔案控制權。

位元組流讀取:FileInputStream

姿勢一:單 byte 讀取(教學用,極慢)


try (FileInputStream fis = new FileInputStream("e:\\a.txt")) {
    byte[] data = new byte[1024];
    int idx = 0, b;
    while ((b = fis.read()) != -1) { // -1 表示 EOF
        data[idx++] = (byte) b;
    }
    String content = new String(data, 0, idx, StandardCharsets.UTF_8);
    System.out.println(content);
}

每次 read() 都是系統呼叫,1MB 檔案需 100 萬次切換,嚴禁生產使用。

姿勢二:批量讀取 byte[](標準高效姿勢)


try (FileInputStream fis = new FileInputStream("e:\\a.txt")) {
    byte[] buffer = new byte[8192]; // 8KB 緩衝區
    int len;
    StringBuilder sb = new StringBuilder();
    while ((len = fis.read(buffer)) != -1) {
        sb.append(new String(buffer, 0, len, StandardCharsets.UTF_8));
    }
    System.out.println(sb.toString());
}
  • read(byte[]) 填滿陣列或達 EOF 返回實際讀取長度。
  • 緩衝區大小 4KB-64KB 為宜(磁碟頁面大小倍數)。
  • 配合 StringBuilder 避免字串拼接產生大量暫存物件。

姿勢三:BufferedInputStream 裝飾(推薦生產)


try (BufferedInputStream bis = new BufferedInputStream(
        new FileInputStream("e:\\a.txt"), 8192)) {
    byte[] buffer = new byte[8192];
    int len;
    while ((len = bis.read(buffer)) != -1) {
        // 處理數據
    }
}

雙重緩衝:OS 頁面緩存 + JVM BufferedInputStream 內部緩衝區,效能最強。

字符流讀取:FileReader / BufferedReader

直接按字符讀取(適合小檔案)


try (FileReader fr = new FileReader("e:\\a.txt")) {
    char[] buffer = new char[1024];
    int len;
    while ((len = fr.read(buffer)) != -1) {
        System.out.print(new String(buffer, 0, len));
    }
}

按行讀取:BufferedReader.readLine()(最常用)


try (BufferedReader br = new BufferedReader(
        new InputStreamReader(new FileInputStream("e:\\a.txt"), StandardCharsets.UTF_8))) {
    String line;
    while ((line = br.readLine()) != null) {
        System.out.println(line); // 無換行符
    }
}

Java 11+ 簡化寫法:


// Files.readAllLines 返回 List,適合小檔案全讀入記憶體
List lines = Files.readAllLines(Paths.get("e:\\a.txt"), StandardCharsets.UTF_8);

// Files.lines 返回 Stream,適合大檔案流式處理
try (Stream stream = Files.lines(Paths.get("e:\\a.txt"), StandardCharsets.UTF_8)) {
    stream.filter(l -> l.contains("ERROR")).forEach(System.out::println);
}

位元組流 vs 字符流:選型決策樹

需要讀取檔案
    │
    ├─ 二進制檔案 (圖片、視頻、序列化物件、加密資料)
    │   └─ 必須用 FileInputStream / BufferedInputStream
    │
    └─ 文字檔案 (日誌、配置、原始碼、CSV、JSON)
        ├─ 需按行處理、逐行解析
        │   └─ BufferedReader.readLine() / Files.lines()
        │
        ├─ 需整檔讀入字串 (小檔案)
        │   └─ Files.readString() / readAllLines()
        │
        └─ 簡單全文讀取
            └─ FileReader / BufferedInputStream + 手動解碼

關鍵細節避坑指南

陷阱後果正確做法
忽略 read() 返回值殘留舊資料、長度錯誤嚴格使用返回的 len 截取有效區間
預設編碼讀中文Windows GBK vs Linux UTF-8 亂碼顯式指定 StandardCharsets.UTF_8
大檔案 readAllLinesOOM 記憶體溢出用 Files.lines() 流式處理
未關閉流檔案鎖佔用、檔案刪除失敗try-with-resources 強制關閉
read() 返回 -1 未判斷無限循環while ((len = read()) != -1)

總結

  • 二進制 → BufferedInputStream + byte[] 緩衝區。
  • 文字按行 → BufferedReader.readLine() 或 Files.lines()。
  • 小文字全讀 → Files.readString() / readAllLines()。
  • 編碼:全鏈路顯式 UTF-8。
  • 資源:try-with-resources 零例外關閉。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved