Java IO 流體系總覽
Object
↑
┌────────┴────────┐
│ │
InputStream OutputStream (字節流,處理二進制:圖片、視頻、音頻)
│ │
┌───────┴───────┐ ┌─────┴─────┐
│ │ │ │
FileInputStream ... FileOutputStream ...
│ │
▼ ▼
Reader Writer (字符流,處理文本:TXT、JSON、CSV、XML)
│ │
┌───────┴───────┐ ┌─────┴─────┐
│ │ │ │
FileReader ... FileWriter ...
│ │
▼ ▼
BufferedReader BufferedWriter (緩衝裝飾器,提升性能,按行讀寫)
│ │
▼ ▼
InputStreamReader OutputStreamWriter (字節↔字符橋梁,指定編碼)
讀文件四大核心模式
1. 字節流讀取 (二進制文件)
public static byte[] readBytes(String path) throws IOException {
try (FileInputStream fis = new FileInputStream(path);
ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
byte[] buffer = new byte[8192];
int len;
while ((len = fis.read(buffer)) != -1) {
baos.write(buffer, 0, len);
}
return baos.toByteArray();
}
}
2. 字符流讀取 (文本文件,指定編碼)
public static String readText(String path, Charset charset) throws IOException {
try (InputStreamReader isr = new InputStreamReader(
new FileInputStream(path), charset);
BufferedReader br = new BufferedReader(isr)) {
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line).append(System.lineSeparator());
}
return sb.toString();
}
}
3. 按行讀取 (最常用,內存友好)
// Java 7+ try-with-resources
public static void processLines(String path, Charset charset, Consumer processor)
throws IOException {
try (BufferedReader br = new BufferedReader(
new InputStreamReader(new FileInputStream(path), charset))) {
String line;
while ((line = br.readLine()) != null) {
processor.accept(line);
}
}
}
// Java 8+ Stream API (自動關閉)
public static List readAllLines(String path, Charset charset) throws IOException {
try (Stream lines = Files.lines(Paths.get(path), charset)) {
return lines.collect(Collectors.toList());
}
}
4. 隨機訪問 (大文件斷點續傳、分片讀取)
public static byte[] readRandom(String path, long offset, int length) throws IOException {
try (RandomAccessFile raf = new RandomAccessFile(path, "r")) {
raf.seek(offset);
byte[] buf = new byte[length];
int read = raf.read(buf);
return Arrays.copyOf(buf, read);
}
}
寫文件核心模式
1. 字節流寫入
public static void writeBytes(String path, byte[] data, boolean append) throws IOException {
try (FileOutputStream fos = new FileOutputStream(path, append);
BufferedOutputStream bos = new BufferedOutputStream(fos)) {
bos.write(data);
}
}
2. 字符流寫入 (指定編碼)
public static void writeText(String path, String content, Charset charset, boolean append)
throws IOException {
try (OutputStreamWriter osw = new OutputStreamWriter(
new FileOutputStream(path, append), charset);
BufferedWriter bw = new BufferedWriter(osw)) {
bw.write(content);
}
}
3. 便捷工具類 (Java 7+ NIO.2 Files)
// 一行代碼讀寫 (小文件)
byte[] data = Files.readAllBytes(Paths.get(path));
String text = Files.readString(Paths.get(path), StandardCharsets.UTF_8);
Files.writeString(Paths.get(path), text, StandardCharsets.UTF_8,
StandardOpenOption.CREATE, StandardOpenOption.APPEND);
Files.write(Paths.get(path), data, StandardOpenOption.CREATE, StandardOpenOption.APPEND);
// 大文件流式
try (InputStream in = Files.newInputStream(Paths.get(src));
OutputStream out = Files.newOutputStream(Paths.get(dest),
StandardOpenOption.CREATE, StandardOpenOption.APPEND)) {
in.transferTo(out); // Java 9+ 零拷貝
}
性能對比與選型建議
| 場景 | 推薦方案 | 緩衝區大小 | 關鍵點 |
| 小文本文件 (<10MB) | Files.readString/writeString | -- | 代碼最簡潔,JDK 內部優化 |
| 大文本文件 (行處理) | Files.lines() 或 BufferedReader | 8KB | 流式處理,不載入全量內存 |
| 二進制文件複製 | Files.copy / in.transferTo(out) | -- | OS 級零拷貝,最快 |
| 頻繁追加寫入 | BufferedWriter + APPEND | 8KB-64KB | 減少系統調用 |
| 隨機讀寫 | RandomAccessFile / SeekableByteChannel | -- | 支持 seek() 定位 |
| 高併發日誌 | AsyncFileChannel / Log4j2/Logback | -- | 異步非阻塞,專業日誌框架 |
編碼處理鐵律
- 顯式指定 Charset:
StandardCharsets.UTF_8,永不依賴平台預設編碼
InputStreamReader/OutputStreamWriter 是字節↔字符唯一橋梁
- 屬性文件
Properties.load JDK 11+ 支持 UTF-8,舊版需自行轉碼
- BOM 頭處理:
BOMInputStream (Apache Commons IO) 自動檢測並剝離
資源管理鐵律
// ✅ Java 7+ try-with-resources (自動關閉,異常安全)
try (Resource r = acquire()) { use(r); }
// ✅ Java 8+ Stream 結束自動關閉
try (Stream s = Files.lines(path)) { ... }
// ❌ 手動 close 易漏、異常路徑不關閉
Resource r = acquire();
try { use(r); } finally { if (r != null) r.close(); }
常見坑點避雷
| 坑點 | 後果 | 解決 |
| 未指定編碼讀寫中文 | 亂碼、數據損壞 | 強制 StandardCharsets.UTF_8 |
大文件 readAllBytes | OOM | 流式分塊處理 |
循環中創建 FileWriter | 極慢、文件鎖競爭 | 提取到循環外,用 BufferedWriter |
FileReader 無編碼構造器 | 平台相關行為 | 改用 InputStreamReader(fis, UTF_8) |
| Windows 路徑分隔符硬編碼 | 跨平台失敗 | Paths.get(...) / File.separator |
隨機讀取未檢查 read() 返回值 | 數據截斷 | 循環讀取直到 -1 |
輸出流未 flush() | 數據停留緩衝區 | try-with-resources 自動 flush |
現代化替代方案
- Apache Commons IO:
FileUtils.readFileToString、IOUtils.copy、Tailer 尾部監聽
- Google Guava:
Files.asCharSource(path, UTF_8).readLines()、ByteStreams
- Okio:
Okio.buffer(Okio.source(file)).readUtf8()、現代 Kotlin/Java 首選
- Netty ByteBuf:高性能網絡編程場景
總結
Java 文件讀寫核心在於「字節流處理二進制,字符流處理文本,緩衝流提升性能,編碼顯式指定,資源自動管理」。掌握 Files (NIO.2)、BufferedReader/Writer、InputStreamReader/OutputStreamWriter 三大組合,覆蓋 95% 業務場景。大文件必用流式處理,小文件享受 Files.readString 便利。遵循「零信任編碼、try-with-resources 管理資源、零拷貝傳輸大文件」三大鐵律,構建健壯、高性能、跨平台的文件處理代碼。