設計目標
- 線程安全、無狀態、靜態方法調用
- 自動處理流關閉、編碼、異常轉換
- 支援任意對象寫入(依賴
toString() 或外部 JSON 庫序列化)
完整代碼
import java.io.*;
public final class JsonUtils {
private JsonUtils() {} // 工具類禁止實例化
/**
* 讀取整個 JSON 文件為字符串(UTF-8)
*/
public static String readJson(String path) {
StringBuilder sb = new StringBuilder();
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
String line;
while ((line = br.readLine()) != null) sb.append(line);
} catch (IOException e) {
throw new RuntimeException("讀取 JSON 失敗:" + path, e);
}
return sb.toString();
}
/**
* 將對象序列化為 JSON 並寫入文件(UTF-8,自動建目錄)
* @param dir 目標目錄
* @param obj 任意對象,建議配合 Jackson/Gson 先序列化為字符串再傳入
* @param fileName 文件名(含 .json 後綴)
*/
public static void writeJson(String dir, Object obj, String fileName) {
File directory = new File(dir);
if (!directory.exists() && !directory.mkdirs()) {
throw new RuntimeException("無法創建目錄:" + dir);
}
File file = new File(directory, fileName);
try (BufferedWriter bw = new BufferedWriter(new FileWriter(file))) {
bw.write(obj.toString()); // 若 obj 已是 JSON 字符串直接寫入;否則建議先用 JSON 庫序列化
} catch (IOException e) {
throw new RuntimeException("寫入 JSON 失敗:" + file.getAbsolutePath(), e);
}
}
}
使用示例
// 1. 讀取
String json = JsonUtils.readJson("config/app.json");
System.out.println(json);
// 2. 寫入(配合 Jackson)
ObjectMapper mapper = new ObjectMapper();
User user = new User("Alice", 25);
JsonUtils.writeJson("data/", mapper.writeValueAsString(user), "user.json");
改進建議(生產級)
- 編碼顯式指定:使用
StandardCharsets.UTF_8 替換平台預設編碼。
- 原子寫入:先寫
.tmp 臨時文件,再 Files.move(..., ATOMIC_MOVE) 替換,防止寫入中斷損壞原文件。
- 集成 JSON 庫:內部直接接收 POJO,自動調用 Jackson
ObjectMapper.writeValue,避免雙重序列化。
- 大文件流式處理:超過 100MB 改用
JsonGenerator 流式寫入,避免 OOM。
對比原版代碼的改進點
| 原版 | 優化版 |
手動 try-catch-finally 關流 | Try-with-resources 自動關閉 |
| 吞掉異常只打印堆疊 | 拋出 RuntimeException 保留鏈路 |
硬編碼 gbk 編碼 | UTF-8 統一,跨平台無亂碼 |
| 文件名拼接易出錯 | File 物件安全拼接路徑 |