文本文件讀寫是 Java 開發高頻操作。本文對比 FileReader/BufferedReader、FileWriter/BufferedWriter、FileInputStream/OutputStream 三大體系,強調編碼顯式指定、try-with-resources 自動關閉、追加/覆蓋模式切換,提供可直接落地的工具方法。
public static String readTextFile(File file, String charset) {
if (charset == null) charset = StandardCharsets.UTF_8.name();
if (!file.isFile() || !file.exists()) return null;
try (BufferedReader br = new BufferedReader(
new InputStreamReader(new FileInputStream(file), charset))) {
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line).append(System.lineSeparator());
}
return sb.toString();
} catch (IOException e) {
throw new UncheckedIOException("讀取失敗: " + file, e);
}
}
優點:按行讀取、記憶體友好、自動處理換行符、編碼可控。
進階:大文件逐行處理(不拼接全量字符串)直接在循環內業務邏輯。
public static void writeTextFile(File file, String content, String charset) {
writeTextFile(file, content, charset, false);
}
public static void appendTextFile(File file, String content, String charset) {
writeTextFile(file, content, charset, true);
}
private static void writeTextFile(File file, String content, String charset, boolean append) {
if (charset == null) charset = StandardCharsets.UTF_8.name();
// 父目錄不存在自動創建
File parent = file.getParentFile();
if (parent != null && !parent.exists()) parent.mkdirs();
try (BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(new FileOutputStream(file, append), charset))) {
bw.write(content);
} catch (IOException e) {
throw new UncheckedIOException("寫入失敗: " + file, e);
}
}
關鍵點:
new FileOutputStream(file, true) 開啟追加模式。OutputStreamWriter 顯式指定編碼,避免 FileWriter 隱式平台編碼。file.createNewFile() 非必需,FileOutputStream 會自動創建文件。public static void writeBytes(File file, byte[] data) {
File parent = file.getParentFile();
if (parent != null && !parent.exists()) parent.mkdirs();
try (FileOutputStream fos = new FileOutputStream(file)) {
fos.write(data);
fos.flush();
} catch (IOException e) {
throw new UncheckedIOException("字節寫入失敗: " + file, e);
}
}
// 調用:writeBytes(file, "內容".getBytes(StandardCharsets.UTF_8));
| API | 用法 | 優點 |
|---|---|---|
Files.readString(Path) | String s = Files.readString(path, StandardCharsets.UTF_8); | 一行代碼讀全文,自動關閉 |
Files.writeString(Path, CharSequence, OpenOption...) | Files.writeString(path, content, StandardCharsets.UTF_8, StandardOpenOption.CREATE, StandardOpenOption.APPEND); | 一行寫入/追加,原子性選項 |
Files.lines(Path) | try (Stream<String> lines = Files.lines(path)) { lines.forEach(...); } | 流式逐行處理,自動關閉 |
Files.newBufferedReader/Writer(Path, Charset) | 返回 BufferedReader/Writer | 兼容舊代碼風格,資源安全 |
StandardCharsets.UTF_8 顯式傳遞。file.getParentFile().mkdirs() 防 FileNotFoundException。Files.lines() 流式處理或逐行業務邏輯。flush() 或 StandardOpenOption.SYNC(性能權衡)。UncheckedIOException 保持調用鏈簡潔,上層統一處理。文本讀寫首選 NIO.2 Files 靜態方法(JDK 11+ 最簡潔),舊版本用 字符流 + 緩衝 + 顯式編碼 + try-with-resources。字節流僅用於已編碼的 byte[] 或二進制數據。牢記「編碼顯式、資源自動、大文件流式」三原則,杜絕亂碼與泄漏。