文本文件讀寫是 Java 基礎且高頻操作,正確處理字符編碼、資源關閉、異常安全、大文件效能是生產代碼必備素質。本文提供完整工具類實作,涵蓋創建、追加寫入、多種讀取方式,並對比傳統 IO 與 NIO.2 現代 API。
package com.b510.txt;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
/**
* 文本文件操作工具類
* 線程不安全,多線程環境需外部同步或使用 ThreadLocal
*/
public class MyFile {
private static final String DEFAULT_DIR = "txt/";
private static String currentFilePath;
public static void main(String[] args) throws IOException {
MyFile tool = new MyFile();
for (int i = 0; i < 5; i++) {
tool.createTxtFile("test");
tool.writeTxtFile("顯示的是追加的信息" + i);
System.out.println("*********\n" + tool.readAllText());
}
}
/** 創建文件(含父目錄),返回是否新建 */
public static boolean createTxtFile(String name) throws IOException {
Path dir = Paths.get(DEFAULT_DIR);
Files.createDirectories(dir); // 自動創建多級目錄
Path file = dir.resolve(name + ".txt");
currentFilePath = file.toString();
return Files.notExists(file) && Files.createFile(file) != null;
}
/** 追加寫入 (自動換行),指定 UTF-8 編碼 */
public static boolean writeTxtFile(String newStr) throws IOException {
if (currentFilePath == null) throw new IllegalStateException("請先調用 createTxtFile");
Path file = Paths.get(currentFilePath);
// 追加模式、創建不存在、UTF-8
Files.write(file, (newStr + System.lineSeparator()).getBytes(StandardCharsets.UTF_8),
StandardOpenOption.CREATE, StandardOpenOption.APPEND);
return true;
}
/** 讀取全部內容為單一字符串 (小文件適用) */
public String readAllText() throws IOException {
if (currentFilePath == null) return "";
return Files.readString(Paths.get(currentFilePath), StandardCharsets.UTF_8);
}
/** 按行讀取 (大文件、流式處理) */
public void readLines(Consumer<String> lineHandler) throws IOException {
if (currentFilePath == null) return;
try (BufferedReader br = Files.newBufferedReader(Paths.get(currentFilePath), StandardCharsets.UTF_8)) {
String line;
while ((line = br.readLine()) != null) lineHandler.accept(line);
}
}
// ===== 以下為傳統 IO 寫法 (教學參考) =====
@Deprecated
public static boolean writeTxtFileLegacy(String newStr) throws IOException {
if (currentFilePath == null) throw new IllegalStateException("未初始化文件");
File file = new File(currentFilePath);
StringBuilder buf = new StringBuilder();
// 讀取原內容
try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8))) {
String line;
while ((line = br.readLine()) != null) buf.append(line).append(System.lineSeparator());
}
buf.append(newStr).append(System.lineSeparator());
// 寫入
try (PrintWriter pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8))) {
pw.write(buf.toString());
}
return true;
}
}
| 場景 | 推薦 API (NIO.2) | 傳統 IO 寫法 | 核心優勢 |
|---|---|---|---|
| 小文件全讀 | Files.readString(path, charset) | BufferedReader 循環 | 單行、自動關閉、編碼顯式 |
| 小文件全寫/追加 | Files.write(path, bytes, APPEND) | FileOutputStream + PrintWriter | 原子選項、自動刷新、無需手動 close |
| 大文件流式讀取 | Files.newBufferedReader(path) + try-with-resources | BufferedReader + 手動 close | 資源自動管理、異常安全 |
| 大文件流式寫入 | Files.newBufferedWriter(path, APPEND) | PrintWriter + 手動 flush/close | 緩衝自動、編碼統一 |
| 目錄/文件操作 | Files.createDirectories(), Files.deleteIfExists() | File.mkdirs(), file.delete() | 異常信息豐富、符號鏈接感知 |
| 現象 | 原因 | 解決 |
|---|---|---|
| 中文亂碼 | 讀寫編碼不一致、或用平台預設編碼 | 全鏈路顯式 StandardCharsets.UTF_8 |
| 內容被截斷 | 未 flush/close、緩衝區未寫入磁碟 | try-with-resources 自動關閉刷新 |
| FileNotFoundException | 父目錄不存在、路徑分隔符錯誤 | Files.createDirectories(parent)、Paths.get() |
| 併發寫入丟數據 | 多線程同時 Append 無同步 | 文件鎖 FileChannel.lock()、或單線程寫入隊列 |
| 大文件 OOM | readAllBytes/readString 載入整文件 | 流式處理 Files.lines()/newBufferedReader() |
現代 Java (JDK 7+) 應優先使用 java.nio.file.Files 靜態方法配合 try-with-resources,實現編碼顯式、資源自動管理、異常安全、代碼簡潔。傳統 java.io 僅用於維護舊代碼或特殊場景 (如需要 RandomAccessFile 隨機讀寫)。掌握 NIO.2 核心 API 是寫出健壯文件操作代碼的基石。