使用Gson解析NDJSON文件中的多个JSON记录


使用gson解析ndjson文件中的多个json记录

本文详细介绍了如何在J*a中利用Gson库解析NDJSON(换行符分隔的JSON)文件,以读取并映射文件中的所有独立JSON记录到对应的DTO对象列表中。针对一次性只能读取一个记录的问题,文章提出了基于JsonReader的循环读取策略,并强调了reader.peek()方法在判断文件末尾时的关键作用,同时提供了完整的示例代码和重要注意事项。

理解NDJSON格式与Gson的初始挑战

NDJSON(Newline Delimited JSON)是一种特殊的数据格式,其中每行都是一个独立的、有效的JSON对象,各行之间通过换行符分隔。与传统的JSON数组不同,NDJSON文件本身并非一个单一的JSON数组,而是多个JSON对象的集合。

当尝试使用Gson库解析NDJSON文件时,常见的初学者误区是直接调用gson.fromJson(reader, YourDTO.class)。例如,对于一个包含多条客户记录的customer.json文件:

// Record # 1
{
 "profile":{
      "salutation":"Mr",
      "title":null,
      "company":null
   },
   "phone":{
      "home_phone":null
   },
   "addresses":[
      {
         "address_id":"1",
         "first_name":"Veronica"
      }
   ],
   "orders":{
      "placed_orders_count":2
   }
}
// Record # 2
{
    "profile":{
      "salutation":null,
      "title":null
   },
   "phone":{
      "home_phone":null
   },
   "addresses":[
      {
         "address_id":"2",
         "title":""
      }
   ],
   "orders":{
      "placed_orders_count":0
   }
}
// ... 更多记录

如果使用以下代码尝试读取:

import com.google.gson.Gson;
import com.google.gson.stream.JsonReader;
import j*a.io.FileReader;
import j*a.io.IOException;

// 假设 CustomerFeedDTO 已经定义
// ...

public class InitialNdjsonReaderExample {
    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);
            // 后续的记录将无法读取到,因为fromJson方法在读取完一个完整的JSON对象后就会停止。
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

这段代码只会成功解析文件中的第一个JSON对象,因为gson.fromJson()方法在读取完一个完整的JSON对象后就会停止。为了读取所有记录,我们需要一种机制来逐个处理文件中的每个JSON对象。

解决方案:循环读取与JsonReader

要正确解析NDJSON文件中的所有记录,核心思想是利用JsonReader的流式读取特性,通过循环逐个解析JSON对象。

aspx1财付通支付接口源码 aspx1财付通支付接口源码

本支付接口的特点,主要是用xml文件来记录订单详情和支付详情。代码比较简单,只要将里面的商户号、商户key换成你自己的,将回调url换成你的网站,就可以使用了。通过这个实例也可以很好的了解一般在线支付接口的基本工作原理。其中的pay.config文件记录的是支付详情,order.config是订单详情

aspx1财付通支付接口源码 0 查看详情 aspx1财付通支付接口源码

以下是实现这一目标的详细步骤和示例代码:

  1. 初始化JsonReader和Gson: 创建Gson实例和指向NDJSON文件的JsonReader。
  2. 设置宽松模式: 调用reader.setLenient(true)。这在处理一些非严格符合JSON规范的输入时非常有用,例如可能存在注释或未引用的字段名等。对于NDJSON文件,虽然通常是严格的,但开启此模式可以增加兼容性。
  3. 循环读取: 使用while (reader.peek() != JsonToken.END_DOCUMENT)作为循环条件。
    • reader.peek()方法用于查看下一个令牌的类型,而不会实际消耗它。
    • JsonToken.END_DOCUMENT表示已经到达JSON文档的末尾。通过检查这个令牌,我们可以确保在文件完全读取完毕后安全地退出循环。
  4. 解析并添加: 在循环内部,每次迭代都调用gson.fromJson(reader, CustomerFeedDTO.class)来解析当前行的JSON对象,并将其添加到预先创建的List中。
import com.google.gson.Gson;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken; // 导入 JsonToken
import j*a.io.FileReader;
import j*a.io.IOException;
import j*a.util.ArrayList;
import j*a.util.List;
import j*a.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; }
    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 +
               '}';
    }
}

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

        // 使用 try-with-resources 确保资源自动关闭
        try (JsonReader reader = new JsonReader(new FileReader("customer.json"))) {
            // 启用宽松模式,以处理可能存在的非严格JSON格式
            reader.setLenient(true);

            // 循环读取直到文档结束
            while (reader.peek() != JsonToken.END_DOCUMENT) {
                CustomerFeedDTO customerFeedDTO = gson.fromJson(reader, CustomerFeedDTO.class);
                customerFeedDTOs.add(customerFeedDTO);
                System.out.println("成功读取记录: " + customerFeedDTO); // 打印每条记录以验证
            }

            System.out.println("\n所有记录读取完毕。总计 " + customerFeedDTOs.size() + " 条记录。");

        } catch (IOException e) {
            System.err.println("读取文件时发生错误: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

DTO类定义

为了成功映射NDJSON数据,需要一个对应的J*a数据传输对象(DTO)类。根据提供的NDJSON结构,一个示例的CustomerFeedDTO可以定义如下:

import j*a.util.ArrayList;
import j*a.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 (必须提供,Gson通过反射调用它们进行数据绑定)
    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 +
               '}';
    }
}

注意: 实际应用中,Map 和 ArrayList> 可以被更具体的DTO类或泛型类型替换,以实现更强类型的数据访问和更清晰的代码结构。例如,profile可以是一个ProfileDTO对象,addresses可以是一个List,这样可以更好地封装数据并提供类型安全。

注意事项

  1. reader.setLenient(true)的重要性: 此方法允许JsonReader在解析JSON时更加宽容,例如接受未引用的名称、单引号字符串、C风格注释等。虽然NDJSON规范通常要求严格的JSON,但实际文件中可能存在一些不规范的格式。开启此模式可以提高解析的健壮性。

  2. reader.peek()与reader.hasNext()的比较:JsonReader确实有一个hasNext()方法,但它在到达文档末尾时可能会抛出IllegalStateException。相比之下,reader.peek() != JsonToken.END_DOCUMENT是一种更安全、更推荐的判断文件末尾的方式,它通过检查下一个令牌类型来避免异常。

  3. 资源管理:try-with-resources: 在处理文件I/O时,确保FileReader和JsonReader等资源被正确关闭至关重要,以防止资源泄露。J*a 7及更高版本提供的try-with-resources语句是管理这些可关闭资源的最佳实践,它能确保在try块结束时(无论正常结束还是异常结束)自动关闭资源。

  4. 异常处理: 文件读取和JSON解析过程中可能会出现IOException或JsonSyntaxException等异常。在生产代码中,应提供健壮的异常处理机制,例如记录错误日志、向用户提供友好的错误信息或采取恢复措施。

以上就是使用Gson解析NDJSON文件中的多个JSON记录的详细内容,更多请关注其它相关文章!


# js  # json  # java  # 新媒体视频营销推广  # 网店营销和推广  # 靠谱的公司网站建设推广  # 永宁网络推广网站  # 岳阳网站优化哪家强  # 喜利得网站建设  # 推广网站排名优化SEO教程  # 扬州推广网站效果怎么样  # 温州网站如何做推广运营  # 京东seo来源  # 实际应用  # 配置文件  # 商户  # 文档  # 是一种  # 就会  # 是一个  # 令牌  # 第一个  # 多个  # json数组  # 数据访问  # google  # stream  # ai  # go 


相关栏目: 【 Google疑问12 】 【 Facebook疑问10 】 【 优化推广96088 】 【 技术知识133117 】 【 IDC资讯59369 】 【 网络运营7196 】 【 IT资讯61894


相关推荐: 漫蛙manwa官网浏览入口_漫蛙漫画网页版访问链接  无人机考证官网 中国民航无人机考证官网登录入口  基于 Flink 和 Kafka 实现高效流处理:连续查询与时间窗口  《豆瓣》私信用户方法  Python定时发送QQ消息  解决SQLAlchemy模型跨文件关联的Linter兼容性指南  Firefox OS应用开发:解决XMLHttpRequest跨域请求阻塞问题  苹果如何下载nanobanana  如何在CSS中清除浮动解决背景颜色不包裹内容问题_clear after技巧  如何使用CSS Grid实现“大方块左侧,小方块右侧垂直堆叠”的水平布局  Google Cloud Functions 时区处理指南:理解与最佳实践  拷贝漫画2025网页版入口 拷贝漫画官网免费看全集  TikTok笔记文字无法编辑如何解决 TikTok笔记文字编辑优化方法  可米酷漫画在线阅读入口_ 可米酷漫画官网直达链接  抖音号已注销怎么解绑企业认证?不解绑企业认证会怎样?  韩小圈网页版PC端入口 韩小圈网页版官方网站入口  《领英》查看屏蔽名单方法  申通快件单号查询平台 申通包裹物流动态跟踪  《密马》发布账号方法  Linux如何开发轻量级数据服务模块_Linux服务化设计  谷歌浏览器如何查找和删除恶意软件 谷歌浏览器内置安全清理工具使用教程  优化Leaflet弹出层图片显示:条件渲染策略  Win10怎么设置快速启动 Win10开启快速启动设置方法  126邮箱申请入口官网_126邮箱注册免费登录2025  顺丰快递怎么查物流_顺丰快递物流信息实时查询操作指南  重返未来:1999卡戎全方位攻略  申通快递查询 申通物流快递单实时查询入口  奥克斯空调不制热啥毛病_奥克斯空调不制热原因分析及解决技巧  Mac怎么关闭按键声音_Mac键盘打字音效设置  win11如何开启单声道音频 Win11为听障用户合并左右声道【辅助】  rabbitmq 持久化有什么缺点?  Golang如何使用gRPC拦截器实现日志收集_Golang gRPC拦截器日志收集实践  《花瓣》创建专辑方法  B站怎么开|直播| B站|直播|申请需要什么条件【新手必看】  微信客户端怎么查看二维码_微信客户端个人二维码查看方法  TikTok视频播放中断怎么办 TikTok播放异常修复方法  创客贴登录页面入口 创客贴网页版最新网址链接  实现可重用自定义Python Range类  Python自动化抓取GBGB赛狗比赛结果:日期范围与赛道筛选教程  《洛克王国:世界》国家队搭配攻略  多闪APP官方下载安装入口_多闪最新版本获取入口  电脑视频号|直播|如何分享屏幕  QQ网站入口直接登录 QQ官方正版登录页面  5G和6G的连接密度有什么区别 6G每平方公里能连接多少设备  解决PHP MySQL数据库更新无响应:SQL查询语法错误解析  智学网app怎么登录忘记密码_智学网app忘记密码找回与重新登录操作方法  告别阻塞等待:如何使用GuzzlePromises优雅处理PHP异步操作,提升应用响应速度  从J*a应用程序中导出MySQL表数据的技术指南  在Dash应用中自定义HTML标题和网站图标  C++ virtual析构函数作用_C++基类虚析构函数防止内存泄漏 

 2025-12-02

了解您产品搜索量及市场趋势,制定营销计划

同行竞争及网站分析保障您的广告效果

点击免费数据支持

提交您的需求,1小时内享受我们的专业解答。

运城市盐湖区信雨科技有限公司


运城市盐湖区信雨科技有限公司

运城市盐湖区信雨科技有限公司是一家深耕海外推广领域十年的专业服务商,作为谷歌推广与Facebook广告全球合作伙伴,聚焦外贸企业出海痛点,以数字化营销为核心,提供一站式海外营销解决方案。公司凭借十年行业沉淀与平台官方资源加持,打破传统外贸获客壁垒,助力企业高效开拓全球市场,成为中小企业出海的可靠合作伙伴。

 8156699

 13765294890

 8156699@qq.com

Notice

We and selected third parties use cookies or similar technologies for technical purposes and, with your consent, for other purposes as specified in the cookie policy.
You can consent to the use of such technologies by closing this notice, by interacting with any link or button outside of this notice or by continuing to browse otherwise.