json文件大小为10G左右,对于这种超大的json使用jackson的objectmapper一把映射到java对象是不太可行的,内存一般都会溢出。此时需要使用jackson的JsonParser从文件中逐个token去读取。一般大json中都会存在某个数组中有超多的数据记录,我们需要解决的就是记录当前token路径,在读取到超大json数组时,再利用逐条数据读取mapper.readTree(jsonParser)逐条读取数据,利用数组缓存一定量的数据后,写入数据库后继续读取,知道json数组数据读取结束。
这里关键的是记录当前json的token的路径,以方便地利用mapper.readTree(jsonParser)读取任意的子节点数据。
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import sarifreport.Result;
import java.io.File;
import java.io.IOException;
public class Main {
public static void main(String [] args){
long start = System.currentTimeMillis();
try {
ObjectMapper mapper = new ObjectMapper();
JsonFactory jsonFactory = new JsonFactory();
JsonParser jsonParser = jsonFactory.createParser(
new File("E:/result2.json"));
JsonPath path = new JsonPath();
while (jsonParser.nextToken() != null) {
traverse(jsonParser, 0,path,mapper);
}
jsonParser.close();
System.out.println((System.currentTimeMillis()-start)/1000+"秒");
} catch (IOException e) {
e.printStackTrace();
}
}
private static void traverse(JsonParser jsonParser, int depth, JsonPath path, ObjectMapper mapper) throws IOException {
JsonToken token = jsonParser.getCurrentToken();
if (token == null) {
return;
}
setPath(jsonParser,depth,path);
if (path.toString().equals("root.runs[i].results[i]")) {
while (jsonParser.nextToken() == JsonToken.START_OBJECT) {
JsonNode jsonNode = mapper.readTree(jsonParser);
// 此处可以读取一定数量的数据后入库
System.out.println(jsonNode.toPrettyString());
}
token = jsonParser.getCurrentToken();
}
// Recursive call for nested structures
if (token == JsonToken.START_OBJECT || token == JsonToken.START_ARRAY) {
while (jsonParser.nextToken() != null && jsonParser.getCurrentToken() != JsonToken.END_OBJECT
&& jsonParser.getCurrentToken() != JsonToken.END_ARRAY) {
traverse(jsonParser, depth + 1,path,mapper);
}
}
}
/**
* 同一个depth只记录一个node
* @param jsonParser
* @param depth
* @param path
* @throws IOException
*/
private static void setPath(JsonParser jsonParser, int depth, JsonPath path) throws IOException {
JsonToken token = jsonParser.getCurrentToken();
if (path.nodeLink.size() > depth+1) {
path.nodeLink.subList(depth+1,path.nodeLink.size()).clear();
}
JsonPath.Node prefixNode = path.nodeLink.size()>=(depth+1)?path.nodeLink.get(depth):null;
switch (token) {
case FIELD_NAME:
if (prefixNode != null) {
prefixNode.nodeType = JsonPath.NODE_FIELD;
prefixNode.nodeName = jsonParser.getCurrentName();
} else {
JsonPath.Node node = new JsonPath.Node();
node.nodeType = JsonPath.NODE_FIELD;
node.nodeName = jsonParser.getCurrentName();
path.nodeLink.add(node);
}
break;
case START_ARRAY:
if (prefixNode != null && JsonPath.NODE_FIELD.equals(prefixNode.nodeType)) {
prefixNode.nodeName = prefixNode.nodeName+"[i]";
} else {
JsonPath.Node node = new JsonPath.Node();
node.nodeType = JsonPath.NODE_ARRAY;
path.nodeLink.add(node);
}
break;
case START_OBJECT:
if (prefixNode != null && JsonPath.NODE_FIELD.equals(prefixNode.nodeType)) {
prefixNode.nodeName = prefixNode.nodeName+".";
} else {
JsonPath.Node node = new JsonPath.Node();
node.nodeType = JsonPath.NODE_OBJECT;
path.nodeLink.add(node);
}
break;
}
}
}
import java.util.LinkedList;
public class JsonPath {
public static String NODE_ARRAY = "array";
public static String NODE_OBJECT = "object";
public static String NODE_FIELD = "field";
public LinkedList<Node> nodeLink = new LinkedList<>();
public static class Node{
public String nodeName;
public String nodeType;
}
@Override
public String toString() {
if (this.nodeLink == null || nodeLink.isEmpty()) {
return "";
}
StringBuilder path = new StringBuilder();
for (int i = 0; i < nodeLink.size(); i++ ) {
Node node = this.nodeLink.get(i);
if (node == null) {
continue;
}
if (i == 0) {
if (NODE_ARRAY.equals(node.nodeType)) {
path.append("root[i]");
} else {
path.append("root");
}
}
if (NODE_ARRAY.equals(node.nodeType)) {
path.append("[i]");
}else if (NODE_OBJECT.equals(node.nodeType)) {
path.append(".");
} else if (NODE_FIELD.equals(node.nodeType)) {
path.append(node.nodeName);
}
}
return path.toString();
}
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>BigJsonDeal</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>19</maven.compiler.source>
<maven.compiler.target>19</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.16.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.jsonschema2pojo</groupId>
<artifactId>jsonschema2pojo-maven-plugin</artifactId>
<version>1.2.1</version>
<configuration>
<sourceDirectory>${basedir}/src/main/resources/schema</sourceDirectory>
<targetProject>${basedir}/src/main/java</targetProject>
<targetPackage>com.example.types</targetPackage>
</configuration>
</plugin>
</plugins>
</build>
</project>
jsonschema2pojo为一个根据json结构生成java的pojo代码的工具,对于复杂json生成pojo十分省时间。