java實現(xiàn)讀寫json文件的示例詳解
1. 項目背景詳細介紹
隨著現(xiàn)代應用對數(shù)據(jù)交換和配置管理需求的增加,JSON(JavaScript Object Notation)已成為最流行的數(shù)據(jù)格式之一。其結(jié)構(gòu)清晰、可讀性高、跨語言支持廣泛,適用于配置文件、日志輸出、前后端數(shù)據(jù)交互等多種場景。Java 平臺上,雖然原生沒有提供對 JSON 的直接支持,但通過第三方庫(如 Jackson、Gson、Fastjson 等),可以非常便捷地實現(xiàn) JSON 文件的讀寫和對象映射。
本項目旨在通過一個簡單的“用戶配置”示例,全面展示 Java 讀寫 JSON 文件的端到端流程,包括:定義數(shù)據(jù)模型、使用 Jackson 庫讀寫 JSON 文件、異常處理與單元測試等。文章適合 Java 初學者,以及希望掌握 JSON 操作的開發(fā)者,既可作為博客,也可用于課堂教學。
2. 項目需求詳細介紹
2.1 功能需求
1.讀取 JSON 文件
- 從指定路徑加載 JSON 文件;
- 將 JSON 內(nèi)容解析為 Java 對象。
2.寫入 JSON 文件
- 將 Java 對象序列化為 JSON 字符串;
- 寫入指定路徑的文件,支持覆蓋與追加兩種模式。
3.數(shù)據(jù)模型定義
- 定義 UserConfig 類,包含多種字段類型(字符串、整數(shù)、列表、嵌套對象等);
- 通過注解或配置,實現(xiàn)字段與 JSON 鍵的靈活映射。
4.異常與校驗
- 讀取異常(文件未找到、格式錯誤)應捕獲并給出友好提示;
- 寫入時處理 I/O 錯誤與磁盤空間不足情況;
- 對必需字段進行非空校驗。
5.單元測試與示例
- 提供 JUnit 測試,驗證讀寫邏輯正確性;
- 包含示例主程序,演示整個流程。
2.2 性能與非功能需求
性能:處理 1 萬條配置記錄的 JSON 文件,讀取/寫入時間 < 200ms;
可維護性:模塊化設計,代碼清晰注釋詳盡;
易用性:API 簡單直觀,README 指南完整;
兼容性:支持 Java 8 及以上版本;
3. 相關(guān)技術(shù)詳細介紹
1.Jackson
- 最流行的 Java JSON 處理庫;
- 提供 ObjectMapper,支持注解方式(@JsonProperty、@JsonInclude 等);
- 支持流式(Streaming)、樹模型(Tree Model)、數(shù)據(jù)綁定(Data Binding)多種用法。
2.Gson / Fastjson 簡述
- Gson:Google 開源,API 簡潔,但對泛型支持需 TypeToken;
- Fastjson:阿里巴巴開源,性能較好,但安全性需注意。
3.Java I/O 與 NIO
- 使用 Files、Paths 等簡單 API;
- 對大文件可采用 NIO 通道和緩沖區(qū)優(yōu)化。
4.JUnit 5
- 單元測試框架,用于驗證 JSON 讀寫功能;
- 支持斷言、異常測試、臨時文件夾規(guī)則等。
4. 實現(xiàn)思路詳細介紹
1.項目結(jié)構(gòu)
json-demo/
├─ src/
│ ├─ main/
│ │ ├─ java/com/example/json/
│ │ │ ├─ model/UserConfig.java
│ │ │ ├─ util/JsonUtils.java
│ │ │ └─ App.java
│ └─ test/
│ └─ java/com/example/json/
│ └─ JsonUtilsTest.java
└─ pom.xml
2.核心流程
- 定義 UserConfig:包括 id、name、email、roles(列表)、profile(嵌套對象)等字段;
- 在 JsonUtils 中封裝 readJson(path, Class<T>) 與 writeJson(path, obj, boolean append) 方法;
- 在 App 中調(diào)用上述工具方法,實現(xiàn)讀取 → 修改 → 寫入的示例流程;
- 使用 JUnit 測試讀寫結(jié)果與異常處理。
3.字段映射與注解
- 使用 @JsonProperty("user_id") 映射字段名;
- 配置 ObjectMapper 忽略未知屬性、忽略空字段。
4.大文件性能優(yōu)化
- 對于超大 JSON 文件(>100MB),采用 Jackson Streaming API:JsonParser / JsonGenerator;
- 結(jié)合 BufferedInputStream 與 BufferedOutputStream,減少 I/O 調(diào)用次數(shù)。
5.異常處理策略
- 捕獲 IOException、JsonProcessingException,包裝為自定義 JsonException;
- 在調(diào)用處進行區(qū)分處理:提示用戶、重試或退出。
5. 完整實現(xiàn)代碼
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" ...>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>json-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!-- Jackson 核心 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.2</version>
</dependency>
<!-- JUnit 5 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.9.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M7</version>
</plugin>
</plugins>
</build>
</project>
java代碼
// ========== src/main/java/com/example/json/model/UserConfig.java ==========
package com.example.json.model;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;
import java.util.Map;
/**
* 用戶配置模型
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
public class UserConfig {
@JsonProperty("user_id")
private int id;
private String name;
private String email;
private List<String> roles;
private Map<String, Object> profile;
// 構(gòu)造方法、getter、setter 省略
}
// ========== src/main/java/com/example/json/util/JsonUtils.java ==========
package com.example.json.util;
import com.example.json.model.UserConfig;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
/**
* JSON 讀寫工具類
*/
public class JsonUtils {
private static final ObjectMapper MAPPER = new ObjectMapper();
static {
MAPPER.configure(SerializationFeature.INDENT_OUTPUT, true);
MAPPER.configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, true);
}
/**
* 讀取 JSON 文件到指定類型對象
*/
public static <T> T readJson(String filePath, Class<T> clazz) throws JsonException {
try {
return MAPPER.readValue(new File(filePath), clazz);
} catch (IOException e) {
throw new JsonException("讀取 JSON 文件失敗: " + filePath, e);
}
}
/**
* 寫入對象為 JSON 文件
* @param append 是否追加,true 時在文件末尾追加;false 覆蓋寫入
*/
public static void writeJson(String filePath, Object obj, boolean append) throws JsonException {
try (Writer writer = new BufferedWriter(new FileWriter(filePath, append))) {
MAPPER.writeValue(writer, obj);
} catch (IOException e) {
throw new JsonException("寫入 JSON 文件失敗: " + filePath, e);
}
}
/**
* 大文件流式寫入示例
*/
public static void writeJsonStream(String filePath, List<UserConfig> list) throws JsonException {
JsonFactory factory = new JsonFactory();
try (JsonGenerator gen = factory.createGenerator(new File(filePath), JsonFactory.Feature.WRITE_BIGDECIMAL_AS_PLAIN)) {
gen.writeStartArray();
for (UserConfig cfg : list) {
MAPPER.writeValue(gen, cfg);
}
gen.writeEndArray();
} catch (IOException e) {
throw new JsonException("流式寫入 JSON 失敗: " + filePath, e);
}
}
}
// ========== src/main/java/com/example/json/util/JsonException.java ==========
package com.example.json.util;
/**
* JSON 操作異常
*/
public class JsonException extends Exception {
public JsonException(String message, Throwable cause) {
super(message, cause);
}
}
// ========== src/main/java/com/example/json/App.java ==========
package com.example.json;
import com.example.json.model.UserConfig;
import com.example.json.util.JsonUtils;
import com.example.json.util.JsonException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
public class App {
public static void main(String[] args) {
String path = "data/user_config.json";
try {
// 1. 讀取現(xiàn)有配置
UserConfig cfg = JsonUtils.readJson(path, UserConfig.class);
System.out.println("讀取配置: " + cfg);
// 2. 修改并寫回
cfg.setRoles(Arrays.asList("admin", "user"));
Map<String,Object> profile = new HashMap<>();
profile.put("age", 30);
profile.put("address", "北京");
cfg.setProfile(profile);
JsonUtils.writeJson(path, cfg, false);
System.out.println("寫入配置完成");
} catch (JsonException e) {
e.printStackTrace();
}
}
}
// ========== src/test/java/com/example/json/JsonUtilsTest.java ==========
package com.example.json;
import com.example.json.model.UserConfig;
import com.example.json.util.JsonUtils;
import com.example.json.util.JsonException;
import org.junit.jupiter.api.*;
import java.nio.file.*;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class JsonUtilsTest {
private final String testFile = "target/test_config.json";
@BeforeAll
void init() throws Exception {
Files.createDirectories(Paths.get("target"));
}
@Test
void testReadWrite() throws JsonException {
UserConfig cfg = new UserConfig();
cfg.setId(100);
cfg.setName("測試");
JsonUtils.writeJson(testFile, cfg, false);
UserConfig read = JsonUtils.readJson(testFile, UserConfig.class);
Assertions.assertEquals(100, read.getId());
Assertions.assertEquals("測試", read.getName());
}
@Test
void testReadNotFound() {
Assertions.assertThrows(JsonException.class, () -> {
JsonUtils.readJson("nonexistent.json", UserConfig.class);
});
}
}6. 代碼詳細解讀
UserConfig:使用 Jackson 注解映射 JSON 字段,包含基本類型、列表、嵌套 Map。
JsonUtils.readJson:封裝 ObjectMapper.readValue,處理文件 I/O 與映射異常。
JsonUtils.writeJson:使用 BufferedWriter 控制覆蓋或追加模式,將對象序列化為格式化 JSON。
JsonUtils.writeJsonStream:演示流式寫入大文件,逐條序列化以降低內(nèi)存占用。
JsonException:統(tǒng)一包裝 JSON 相關(guān)異常,調(diào)用方可根據(jù)類型分別處理。
App:示例應用,展示讀取、修改、寫回的完整流程。
JsonUtilsTest:JUnit 5 單元測試,驗證正常讀寫、異常場景,確保工具類可靠。
7. 項目詳細總結(jié)
本項目通過 Jackson 庫與標準 Java I/O,完整實現(xiàn)了對 JSON 文件的讀寫,包括簡單場景與大文件流式場景;通過模塊化工具類、統(tǒng)一異常處理和單元測試,保證了代碼的可維護性與可靠性。項目結(jié)構(gòu)清晰,注釋詳盡,適合快速上手和二次擴展。
8. 項目常見問題及解答
JSON 文件包含未知字段時如何處理?
默認 Jackson 會拋出異常,可通過 MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) 忽略未知字段。
追加模式寫入的 JSON 格式如何保持合法?
追加時需控制文件內(nèi)容格式,可先讀入 List,添加后整體寫回,避免手動追加導致格式錯誤。
大文件讀寫導致 OOM?
對于超大數(shù)組,應使用 Jackson Streaming API,逐條讀寫,避免一次性加載。
如何在 Spring Boot 中集成?
將 JsonUtils 封裝為 @Component,并注入自定義配置的 ObjectMapper 即可。
多線程并發(fā)讀寫如何保證安全?
寫操作時可在工具類中加入 synchronized,或由調(diào)用方通過外部鎖保證;讀操作一般是無狀態(tài)的,可以并發(fā)執(zhí)行。
9. 擴展方向與性能優(yōu)化
支持 YAML / XML:添加 SnakeYAML、Jackson XML 模塊,實現(xiàn)多格式互轉(zhuǎn)。
異步 I/O:結(jié)合 NIO AsynchronousFileChannel,異步讀寫提升吞吐。
緩存機制:對頻繁讀取的配置引入內(nèi)存緩存,定時刷新或文件變更監(jiān)聽。
Schema 校驗:引入 JSON Schema,對輸入輸出進行嚴格校驗,保證數(shù)據(jù)一致性。
分布式配置:集成 Apollo、Spring Cloud Config,將 JSON 文件遷移至配置中心。
大文件并發(fā)處理:結(jié)合多線程分片讀取/寫入,并行序列化。
到此這篇關(guān)于java實現(xiàn)讀寫json文件的示例詳解的文章就介紹到這了,更多相關(guān)java讀寫json內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
IDEA創(chuàng)建父項目和子項目的實現(xiàn)步驟
本文主要介紹了IDEA創(chuàng)建父項目和子項目的實現(xiàn)步驟,文中通過圖文介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2024-07-07
SpringBoot自定義FailureAnalyzer過程解析
這篇文章主要介紹了SpringBoot自定義FailureAnalyzer,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2019-11-11
Java對象初始化過程代碼塊和構(gòu)造器的調(diào)用順序
這篇文章主要介紹了Java對象初始化過程代碼塊和構(gòu)造器的調(diào)用順序,文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下2022-08-08

