new FileInputStream("path") 連接檔案。read() 從流拉取資料到記憶體。close() 釋放檔案控制權。
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 萬次切換,嚴禁生產使用。
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 返回實際讀取長度。StringBuilder 避免字串拼接產生大量暫存物件。
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 內部緩衝區,效能最強。
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));
}
}
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);
}
需要讀取檔案
│
├─ 二進制檔案 (圖片、視頻、序列化物件、加密資料)
│ └─ 必須用 FileInputStream / BufferedInputStream
│
└─ 文字檔案 (日誌、配置、原始碼、CSV、JSON)
├─ 需按行處理、逐行解析
│ └─ BufferedReader.readLine() / Files.lines()
│
├─ 需整檔讀入字串 (小檔案)
│ └─ Files.readString() / readAllLines()
│
└─ 簡單全文讀取
└─ FileReader / BufferedInputStream + 手動解碼
| 陷阱 | 後果 | 正確做法 |
|---|---|---|
| 忽略 read() 返回值 | 殘留舊資料、長度錯誤 | 嚴格使用返回的 len 截取有效區間 |
| 預設編碼讀中文 | Windows GBK vs Linux UTF-8 亂碼 | 顯式指定 StandardCharsets.UTF_8 |
| 大檔案 readAllLines | OOM 記憶體溢出 | 用 Files.lines() 流式處理 |
| 未關閉流 | 檔案鎖佔用、檔案刪除失敗 | try-with-resources 強制關閉 |
| read() 返回 -1 未判斷 | 無限循環 | while ((len = read()) != -1) |
BufferedInputStream + byte[] 緩衝區。BufferedReader.readLine() 或 Files.lines()。Files.readString() / readAllLines()。