讲师中心 微信公众号
AI工具推荐 视频效率加速

使用Gson解析ndJson多条记录的完整指南

胖宇大大_2424

胖宇大大_2424

发布时间:2025-12-02 13:15:24

|

233人浏览过

|

来源于php中文网

原创

使用Gson解析ndJson多条记录的完整指南

本文详细介绍了如何使用gson库在java中高效解析包含多条记录的ndjson文件。通过利用`jsonreader`的迭代读取能力和`peek()`方法判断文件结束,结合`setlenient(true)`处理非严格json格式,可以成功将所有ndjson记录映射到对应的dto对象列表中,避免了只读取首条记录的问题,为处理大规模ndjson数据提供了实用的解决方案。

使用Gson解析ndJson多条记录

在处理数据时,ndJson(Newline Delimited JSON)是一种常见的文件格式,它将每个JSON对象独立地放置在文件的一行中,以换行符分隔。当需要使用Java和Gson库解析这类文件时,一个常见的挑战是如何读取并映射文件中的所有记录,而不仅仅是第一条。本文将深入探讨如何高效地实现这一目标。

ndJson格式概述

ndJson文件的特点是每行包含一个完整的JSON对象。例如:

{"id": 1, "name": "Alice"}
{"id": 2, "name": "Bob"}
{"id": 3, "name": "Charlie"}

这种格式在日志处理、数据流传输和大数据分析场景中非常有用,因为它允许逐行处理数据,无需一次性加载整个文件到内存中。

遇到的问题:只读取首条记录

当尝试使用Gson的fromJson()方法直接从FileReader或JsonReader读取ndJson文件时,通常只会成功解析并返回文件中的第一个JSON对象。这是因为fromJson()方法在遇到一个完整的JSON对象后就会停止读取,而不会自动迭代到文件的下一行。

考虑以下常见的错误实现:

import com.google.gson.Gson;
import com.google.gson.stream.JsonReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.Map;
import java.util.ArrayList;

// 假设 CustomerFeedDTO 类已定义
class CustomerFeedDTO {
    private Map<String, ?> profile;
    private Map<String, ?> phone;
    private ArrayList<?> addresses;
    private Map<String, ?> orders;
    private ArrayList<?> customs;

    // Getters and setters (省略)
    @Override
    public String toString() {
        return "CustomerFeedDTO{" +
               "profile=" + profile +
               ", phone=" + phone +
               ", addresses=" + addresses +
               ", orders=" + orders +
               ", customs=" + customs +
               '}';
    }
}

public class NdJsonParserProblem {
    public static void main(String[] args) {
        Gson gson = new Gson();
        try (JsonReader reader = new JsonReader(new FileReader("customer.json"))) {
            // 这种方式只会读取第一个JSON对象
            CustomerFeedDTO customerFeedDTO = gson.fromJson(reader, CustomerFeedDTO.class);
            System.out.println("只读取到第一条记录: " + customerFeedDTO);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

上述代码只会将customer.json文件中的第一个JSON对象映射到CustomerFeedDTO实例中。

Google Chat
Google Chat

使用 Google Chat API 操作聊天室、成员、消息、附件和线程对话,适用于列出聊天室等需求。

下载

解决方案:迭代解析与JsonReader

要正确解析ndJson文件中的所有记录,我们需要利用JsonReader的迭代特性,通过循环逐个读取JSON对象。关键在于使用reader.peek()方法来判断文件是否已到达末尾,并结合reader.setLenient(true)来处理ndJson中可能存在的非严格JSON格式(例如,行与行之间的空白或注释)。

以下是完整的解决方案代码:

import com.google.gson.Gson;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

// 假设 CustomerFeedDTO 类已定义,与上面示例相同
class CustomerFeedDTO {
    private Map<String, ?> profile;
    private Map<String, ?> phone;
    private ArrayList<?> addresses;
    private Map<String, ?> orders;
    private ArrayList<?> customs;

    // Getters and setters
    public Map<String, ?> getProfile() { return profile; }
    public void setProfile(Map<String, ?> profile) { this.profile = profile; }
    // ... 其他getter/setter
    @Override
    public String toString() {
        return "CustomerFeedDTO{" +
               "profile=" + profile +
               ", phone=" + phone +
               ", addresses=" + addresses +
               ", orders=" + orders +
               ", customs=" + customs +
               '}';
    }
}

public class NdJsonParserSolution {
    public static void main(String[] args) {
        List<CustomerFeedDTO> customerFeedDTOs = new ArrayList<>();
        Gson gson = new Gson();

        // 使用try-with-resources确保JsonReader正确关闭
        try (JsonReader reader = new JsonReader(new FileReader("customer.json"))) {
            // 启用宽松模式,以更好地处理ndJson格式,例如允许根级别的值之间没有分隔符
            reader.setLenient(true);

            // 循环读取,直到文件末尾
            // reader.peek() != JsonToken.END_DOCUMENT 是判断文件是否结束的关键
            while (reader.peek() != JsonToken.END_DOCUMENT) {
                // 将当前JSON对象映射到CustomerFeedDTO
                CustomerFeedDTO customerFeedDTO = gson.fromJson(reader, CustomerFeedDTO.class);
                customerFeedDTOs.add(customerFeedDTO);
            }

            // 打印所有解析出的记录
            System.out.println("成功解析所有记录:");
            for (int i = 0; i < customerFeedDTOs.size(); i++) {
                System.out.println("记录 #" + (i + 1) + ": " + customerFeedDTOs.get(i));
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

代码解析:

  1. List<CustomerFeedDTO> customerFeedDTOs = new ArrayList<>();: 创建一个列表来存储所有解析后的CustomerFeedDTO对象。
  2. try (JsonReader reader = new JsonReader(new FileReader("customer.json"))): 使用try-with-resources语句确保JsonReader和FileReader在操作完成后自动关闭,防止资源泄露。
  3. reader.setLenient(true);: 这一行至关重要。ndJson文件通常是多行JSON对象,它们之间只用换行符分隔,而没有逗号等严格的JSON数组分隔符。默认情况下,JsonReader是严格模式,当遇到这种非标准分隔时会抛出异常。setLenient(true)允许JsonReader以更宽松的方式解析,从而能够正确处理ndJson。
  4. while (reader.peek() != JsonToken.END_DOCUMENT): 这是循环读取的核心。
    • reader.peek()方法用于查看下一个令牌的类型,而不会实际消费它。
    • JsonToken.END_DOCUMENT表示已到达JSON文档的末尾。通过检查下一个令牌是否不是文档末尾,我们可以确定是否还有更多的JSON对象可以读取。
    • 注意: 避免使用reader.hasNext()来判断,因为在某些情况下,当到达文档末尾时,hasNext()可能会抛出异常,而不是返回false。peek()方法更加稳健。
  5. CustomerFeedDTO customerFeedDTO = gson.fromJson(reader, CustomerFeedDTO.class);: 在每次循环中,gson.fromJson()方法会从当前的JsonReader位置开始,解析下一个完整的JSON对象,并将其映射到CustomerFeedDTO实例。
  6. customerFeedDTOs.add(customerFeedDTO);: 将解析出的DTO对象添加到列表中。

DTO类结构示例

为了完整性,这里提供CustomerFeedDTO的示例结构,它使用了Map<String, ?>和ArrayList<?>来灵活地处理ndJson中嵌套的、结构可能不完全固定的数据:

import java.util.ArrayList;
import java.util.Map;

public class CustomerFeedDTO {
    // 使用Map来处理结构可能不完全固定的JSON对象
    private Map<String, ?> profile;
    private Map<String, ?> phone;
    // 使用ArrayList来处理JSON数组
    private ArrayList<?> addresses;
    private Map<String, ?> orders;
    private ArrayList<?> customs;

    // 构造函数 (可选)
    public CustomerFeedDTO() {}

    // Getters and Setters
    public Map<String, ?> getProfile() {
        return profile;
    }

    public void setProfile(Map<String, ?> profile) {
        this.profile = profile;
    }

    public Map<String, ?> getPhone() {
        return phone;
    }

    public void setPhone(Map<String, ?> phone) {
        this.phone = phone;
    }

    public ArrayList<?> getAddresses() {
        return addresses;
    }

    public void setAddresses(ArrayList<?> addresses) {
        this.addresses = addresses;
    }

    public Map<String, ?> getOrders() {
        return orders;
    }

    public void setOrders(Map<String, ?> orders) {
        this.orders = orders;
    }

    public ArrayList<?> getCustoms() {
        return customs;
    }

    public void setCustoms(ArrayList<?> customs) {
        this.customs = customs;
    }

    @Override
    public String toString() {
        return "CustomerFeedDTO{" +
               "profile=" + profile +
               ", phone=" + phone +
               ", addresses=" + addresses +
               ", orders=" + orders +
               ", customs=" + customs +
               '}';
    }
}

实际应用中,建议根据JSON的具体结构定义更具体的Java类,而不是广泛使用Map和ArrayList<?>,以获得更好的类型安全性和代码可读性。

总结

通过结合Gson库、JsonReader的迭代能力以及setLenient(true)宽松模式,我们可以有效地解析包含多条记录的ndJson文件。关键在于使用while (reader.peek() != JsonToken.END_DOCUMENT)循环逐个读取JSON对象,并将其映射到Java DTO列表中。这种方法不仅解决了只读取第一条记录的问题,也为处理大规模ndJson数据流提供了健壮且高效的解决方案。在实际开发中,请务必处理IOException,并考虑使用try-with-resources来管理文件资源。

热门AI工具

更多
超级简历WonderCV

一款AI办公效率工具,主要用于免费求职简历模版下载制作,应届生职场人必备简历制作神器,适合需要提升相关任务效率的用户。

讯飞智作

讯飞智作是一款AI视频创作工具,AI文本配音工具,数字人课程、营销视频制作。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

UP简历
UP简历 Hot

一款AI办公效率工具,主要用于基于AI技术的免费在线简历制作工具,适合需要提升相关任务效率的用户。

Laper
Laper Hot

Laper是专为编剧、导演和制片人推出的 AI 原生剧本创作工具。

蛙蛙写作

一款AI论文写作工具,主要用于超级AI智能写作助手,适合需要提升相关任务效率的用户。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

切问学术

切问学术是一款AI论文写作工具,复旦大学NLP团队推出的AI学术智能体。

相关专题

更多
json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

1955

2023.08.07

json是什么
json是什么

JSON是一种轻量级的数据交换格式,具有简洁、易读、跨平台和语言的特点,JSON数据是通过键值对的方式进行组织,其中键是字符串,值可以是字符串、数值、布尔值、数组、对象或者null,在Web开发、数据交换和配置文件等方面得到广泛应用。本专题为大家提供json相关的文章、下载、课程内容,供大家免费下载体验。

2602

2023.08.23

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

896

2023.10.13

go语言处理json数据方法
go语言处理json数据方法

本专题整合了go语言中处理json数据方法,阅读专题下面的文章了解更多详细内容。

2899

2025.09.10

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

5079

2023.08.02

while的用法
while的用法

while的用法是“while 条件: 代码块”,条件是一个表达式,当条件为真时,执行代码块,然后再次判断条件是否为真,如果为真则继续执行代码块,直到条件为假为止。本专题为大家提供while相关的文章、下载、课程内容,供大家免费下载体验。

334

2023.09.25

class在c语言中的意思
class在c语言中的意思

在C语言中,"class" 是一个关键字,用于定义一个类。想了解更多class的相关内容,可以阅读本专题下面的文章。

3116

2024.01.03

python中class的含义
python中class的含义

本专题整合了python中class的相关内容,阅读专题下面的文章了解更多详细内容。

286

2025.12.06

Conan私有仓库搭建教程
Conan私有仓库搭建教程

本专题系统的讲解Conan私有仓库的搭建流程,涵盖仓库服务部署、存储目录配置、用户认证、权限划分和远程地址添加,并介绍内部C++依赖包的上传、下载及版本维护方法。

0

2026.09.22

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
dev.java 官方:Learn Java
dev.java 官方:Learn Java

共0课时 | 0人学习

Java JDBC数据库连接官方教程
Java JDBC数据库连接官方教程

共0课时 | 0人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn