java实现读写json文件的示例详解

 更新时间:2025年05月27日 09:22:54   作者:Katie。  
随着现代应用对数据交换和配置管理需求的增加,JSON(JavaScript Object Notation)已成为最流行的数据格式之一,本文将为大家全面展示 Java 读写 JSON 文件的端到端流程,需要的小伙伴可以了解下

1. 项目背景详细介绍

随着现代应用对数据交换和配置管理需求的增加,JSON(JavaScript Object Notation)已成为最流行的数据格式之一。其结构清晰、可读性高、跨语言支持广泛,适用于配置文件、日志输出、前后端数据交互等多种场景。Java 平台上,虽然原生没有提供对 JSON 的直接支持,但通过第三方库(如 Jackson、Gson、Fastjson 等),可以非常便捷地实现 JSON 文件的读写和对象映射。

本项目旨在通过一个简单的“用户配置”示例,全面展示 Java 读写 JSON 文件的端到端流程,包括:定义数据模型、使用 Jackson 库读写 JSON 文件、异常处理与单元测试等。文章适合 Java 初学者,以及希望掌握 JSON 操作的开发者,既可作为博客,也可用于课堂教学。

2. 项目需求详细介绍

2.1 功能需求

1.读取 JSON 文件

  • 从指定路径加载 JSON 文件;
  • 将 JSON 内容解析为 Java 对象。

2.写入 JSON 文件

  • 将 Java 对象序列化为 JSON 字符串;
  • 写入指定路径的文件,支持覆盖与追加两种模式。

3.数据模型定义

  • 定义 UserConfig 类,包含多种字段类型(字符串、整数、列表、嵌套对象等);
  • 通过注解或配置,实现字段与 JSON 键的灵活映射。

4.异常与校验

  • 读取异常(文件未找到、格式错误)应捕获并给出友好提示;
  • 写入时处理 I/O 错误与磁盘空间不足情况;
  • 对必需字段进行非空校验。

5.单元测试与示例

  • 提供 JUnit 测试,验证读写逻辑正确性;
  • 包含示例主程序,演示整个流程。

2.2 性能与非功能需求

性能:处理 1 万条配置记录的 JSON 文件,读取/写入时间 < 200ms;

可维护性:模块化设计,代码清晰注释详尽;

易用性:API 简单直观,README 指南完整;

兼容性:支持 Java 8 及以上版本;

3. 相关技术详细介绍

1.Jackson

  • 最流行的 Java JSON 处理库;
  • 提供 ObjectMapper,支持注解方式(@JsonProperty、@JsonInclude 等);
  • 支持流式(Streaming)、树模型(Tree Model)、数据绑定(Data Binding)多种用法。

2.Gson / Fastjson 简述

  • Gson:Google 开源,API 简洁,但对泛型支持需 TypeToken;
  • Fastjson:阿里巴巴开源,性能较好,但安全性需注意。

3.Java I/O 与 NIO

  • 使用 Files、Paths 等简单 API;
  • 对大文件可采用 NIO 通道和缓冲区优化。

4.JUnit 5

  • 单元测试框架,用于验证 JSON 读写功能;
  • 支持断言、异常测试、临时文件夹规则等。

4. 实现思路详细介绍

1.项目结构

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 中调用上述工具方法,实现读取 → 修改 → 写入的示例流程;
  • 使用 JUnit 测试读写结果与异常处理。

3.字段映射与注解

  • 使用 @JsonProperty("user_id") 映射字段名;
  • 配置 ObjectMapper 忽略未知属性、忽略空字段。

4.大文件性能优化

  • 对于超大 JSON 文件(>100MB),采用 Jackson Streaming API:JsonParser / JsonGenerator;
  • 结合 BufferedInputStream 与 BufferedOutputStream,减少 I/O 调用次数。

5.异常处理策略

  • 捕获 IOException、JsonProcessingException,包装为自定义 JsonException;
  • 在调用处进行区分处理:提示用户、重试或退出。

5. 完整实现代码

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;
 
    // 构造方法、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. 读取现有配置
            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:演示流式写入大文件,逐条序列化以降低内存占用。

JsonException:统一包装 JSON 相关异常,调用方可根据类型分别处理。

App:示例应用,展示读取、修改、写回的完整流程。

JsonUtilsTest:JUnit 5 单元测试,验证正常读写、异常场景,确保工具类可靠。

7. 项目详细总结

本项目通过 Jackson 库与标准 Java I/O,完整实现了对 JSON 文件的读写,包括简单场景与大文件流式场景;通过模块化工具类、统一异常处理和单元测试,保证了代码的可维护性与可靠性。项目结构清晰,注释详尽,适合快速上手和二次扩展。

8. 项目常见问题及解答

JSON 文件包含未知字段时如何处理?

默认 Jackson 会抛出异常,可通过 MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) 忽略未知字段。

追加模式写入的 JSON 格式如何保持合法?

追加时需控制文件内容格式,可先读入 List,添加后整体写回,避免手动追加导致格式错误。

大文件读写导致 OOM?

对于超大数组,应使用 Jackson Streaming API,逐条读写,避免一次性加载。

如何在 Spring Boot 中集成?

将 JsonUtils 封装为 @Component,并注入自定义配置的 ObjectMapper 即可。

多线程并发读写如何保证安全?

写操作时可在工具类中加入 synchronized,或由调用方通过外部锁保证;读操作一般是无状态的,可以并发执行。

9. 扩展方向与性能优化

支持 YAML / XML:添加 SnakeYAML、Jackson XML 模块,实现多格式互转。

异步 I/O:结合 NIO AsynchronousFileChannel,异步读写提升吞吐。

缓存机制:对频繁读取的配置引入内存缓存,定时刷新或文件变更监听。

Schema 校验:引入 JSON Schema,对输入输出进行严格校验,保证数据一致性。

分布式配置:集成 Apollo、Spring Cloud Config,将 JSON 文件迁移至配置中心。

大文件并发处理:结合多线程分片读取/写入,并行序列化。

到此这篇关于java实现读写json文件的示例详解的文章就介绍到这了,更多相关java读写json内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 一文探索Java文件读写更高效方式

    一文探索Java文件读写更高效方式

    这篇文章主要介绍了一文探索Java文件读写更高效方式,文章围绕主题展开详细的内容介绍,具有一定的参考价值需要的小伙伴可以参考一下
    2022-07-07
  • SpringBoot整合ELK做日志超完整详细教程

    SpringBoot整合ELK做日志超完整详细教程

    本文详细介绍了如何在springboot中快速接入ELK的过程,ELK可以说在实际项目中具有很好的适用价值,不管是小项目,还是中大型项目,都具备普适参考性,值得深入了解和学习,感兴趣的朋友一起看看吧
    2024-01-01
  • Mybatis分解式查询使用方法

    Mybatis分解式查询使用方法

    这篇文章主要介绍了Mybatis分解式查询使用方法,分解式查询就是将一条Sql语句拆分成多条。在 MyBatis 多表查询中,使用连接查询时一个 Sql 语句就可以查询出所有的数据
    2023-04-04
  • IDEA创建父项目和子项目的实现步骤

    IDEA创建父项目和子项目的实现步骤

    本文主要介绍了IDEA创建父项目和子项目的实现步骤,文中通过图文介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-07-07
  • Java超详细介绍封装与访问控制修符

    Java超详细介绍封装与访问控制修符

    封装是一个非常广泛的概念,小到一个属性的封装,大到一个框架或者一个项目的封装,文中通过实例代码将详细介绍封装与访问控制修饰符
    2022-05-05
  • 简单学习Java API 设计实践

    简单学习Java API 设计实践

    API(Application Programming Interface,应用程序编程接口)是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件的以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。需要的可以了解一下
    2019-06-06
  • 详解Java基础之封装

    详解Java基础之封装

    这篇文章主要为大家介绍了Java基础之封装,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-01-01
  • Java8时间接口LocalDateTime详细用法

    Java8时间接口LocalDateTime详细用法

    最近看别人项目源码,发现Java8新的日期时间API很方便强大,所以整理了这篇文章,文中有非常详细的代码示例,对正在学习java的小伙伴们有很好的帮助,需要的朋友可以参考下
    2021-05-05
  • SpringBoot自定义FailureAnalyzer过程解析

    SpringBoot自定义FailureAnalyzer过程解析

    这篇文章主要介绍了SpringBoot自定义FailureAnalyzer,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-11-11
  • Java对象初始化过程代码块和构造器的调用顺序

    Java对象初始化过程代码块和构造器的调用顺序

    这篇文章主要介绍了Java对象初始化过程代码块和构造器的调用顺序,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-08-08

最新评论