如何用Jackson优先读取大JSON文件末尾的Node1.3节点
解决方案:流式解析大JSON并关联日期到数组元素
针对你处理65MB大JSON文件的场景,我给你优化了Jackson的流式解析逻辑,既能高效读取又能按要求先获取日期再处理数组元素。下面是具体实现步骤:
1. 定义目标POJO
首先创建一个POJO类,用来存储最终需要的关联数据:
public class LogEntry { private String logLevel; private int count; private String fromDate; private String toDate; // 无参构造函数(Jackson解析必须) public LogEntry() {} // Getter和Setter方法 public String getLogLevel() { return logLevel; } public void setLogLevel(String logLevel) { this.logLevel = logLevel; } public int getCount() { return count; } public void setCount(int count) { this.count = count; } public String getFromDate() { return fromDate; } public void setFromDate(String fromDate) { this.fromDate = fromDate; } public String getToDate() { return toDate; } public void setToDate(String toDate) { this.toDate = toDate; } // 可选:重写toString方便调试 @Override public String toString() { return "LogEntry{" + "logLevel='" + logLevel + '\'' + ", count=" + count + ", fromDate='" + fromDate + '\'' + ", toDate='" + toDate + '\'' + '}'; } }
2. 优化流式解析代码
修改原有的解析逻辑,重点解决层级遍历和日期缓存的问题,同时跳过无关节点提升效率:
import com.fasterxml.jackson.core.JsonFactory; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import java.io.File; import java.io.IOException; public class TempMain { public static void main(String[] args) throws IOException { JsonFactory jfactory = new JsonFactory(); ObjectMapper mapper = new ObjectMapper(); String fromDate = null; String toDate = null; try (JsonParser jParser = jfactory.createParser(new File("/tmp/file.json"))) { // 遍历根对象,找到"Root Node" while (jParser.nextToken() != JsonToken.END_OBJECT) { String rootField = jParser.getCurrentName(); if ("Root Node".equals(rootField)) { jParser.nextToken(); // 进入Root Node的对象节点 // 遍历Root Node下的字段,找到"Node1" while (jParser.nextToken() != JsonToken.END_OBJECT) { String node1Field = jParser.getCurrentName(); if ("Node1".equals(node1Field)) { jParser.nextToken(); // 进入Node1的对象节点 // 遍历Node1下的所有子节点 while (jParser.nextToken() != JsonToken.END_OBJECT) { String node1ChildField = jParser.getCurrentName(); jParser.nextToken(); // 移动到当前字段的值位置 if ("Node1.3".equals(node1ChildField)) { // 解析日期节点,缓存fromDate和toDate ObjectNode dateNode = mapper.readTree(jParser); fromDate = dateNode.get("fromDate").asText(); toDate = dateNode.get("toDate").asText(); } else if ("Node1.1".equals(node1ChildField)) { // 处理日志数组,逐个解析元素并关联日期 if (jParser.getCurrentToken() == JsonToken.START_ARRAY) { while (jParser.nextToken() != JsonToken.END_ARRAY) { if (jParser.getCurrentToken() == JsonToken.START_OBJECT) { LogEntry entry = mapper.readValue(jParser, LogEntry.class); // 将缓存的日期赋值给当前日志条目 entry.setFromDate(fromDate); entry.setToDate(toDate); // 这里添加你的业务逻辑,比如保存到数据库或集合 System.out.println(entry); } } } } else { // 跳过不需要的节点(比如Node1.2),减少不必要的解析 jParser.skipChildren(); } } } else { // 跳过Root Node下无关的节点 jParser.skipChildren(); } } } else { // 跳过根对象下无关的节点 jParser.skipChildren(); } } } catch (Exception e) { e.printStackTrace(); } } }
关键优化点说明
- 层级精准遍历:原代码直接在根对象查找子字段,会遗漏嵌套在
Root Node->Node1下的目标节点,现在逐层进入嵌套对象,确保能正确捕获Node1.3和Node1.1。 - 日期提前缓存:遇到
Node1.3时立即解析并保存日期,后续处理数组时直接复用,不需要重复读取。 - 高效跳过无关节点:使用
jParser.skipChildren()跳过不需要的节点(如Node1.2),避免浪费资源解析无关内容,尤其适合大文件场景。 - 低内存流式处理:逐个解析数组元素,不会将整个65MB的JSON加载到内存,保证解析过程的内存友好性。
内容的提问来源于stack exchange,提问作者Brajesh Pant
相关产品推荐
相关产品推荐

