Java解析JSON大文件解决方案之JsonReader
Java解析JSON大文件解决方案之JsonReader
一,使用背景
之前遇到一个需求,是需要将一个json文件解析存储到数据库中。一开始测试的时候,json文件的大小都在几兆以内,所以直接将json文件转化为字符串,再转化成JSONObject对象进行处理时不会出现问题,如下所示:
File file = new File("")
try(FileInputStream fileInputStream = new FileInputStream(file)) {int size = fileInputStream.available();byte[] buffer = new byte[size];fileInputStream.read(buffer);String jsonString = new String(buffer, StandardCharsets.UTF_8);jsonString.replaceAll("\n", "");jsonString.replaceAll("\r", "");JSONObject json = JSON.parseObject(jsonString);
}
但是,当出现几十兆文件的时候,这时候就会报出内存溢出的错误
java.lang.OutOfMemoryError: Java heap space
虽然稍微大一点的文件,可以通过调整JVM参数来解决,如下所示
-Xms512m -Xmx2048m
但是这毕竟不是最合理的方法,因为当文件大到一定程度后,字节数组和字符串类型都存在接收不了的情况。因此,只能选择另外的方式,此时,Google的JsonReader是一个不错的解决方案。
二,JsonReader的使用
maven依赖如下:
<dependency><groupId>com.google.code.gson</groupId><artifactId>gson</artifactId><version>2.8.6</version>
</dependency>
JsonReader读取 JSON (RFC 7159) 编码值作为令牌流。 此流包括文字 值(字符串、数字、布尔值和空值)以及开始和 对象和数组的结束分隔符。 令牌被遍历 深度优先顺序,与它们在 JSON 文档中出现的顺序相同。 在 JSON 对象中,名称/值对由单个标记表示。
解析json
创建递归下降解析器 JSON ,首先创建 创建一个入口点方法 JsonReader
.
每个对象类型和每个数组类型都需要一个方法。
- 在 数组处理 方法中,首先调用 beginArray()消耗数组的左括号。 然后创建一个累积值的while循环,在何时终止 hasNext()为false。 最后,通过调用读取数组的右括号 endArray()
- 在 对象处理 方法中,首先调用 beginObject()消耗对象的左大括号。 然后创建一个while循环根据局部变量的名称为其赋值。 这个循环应该在什么时候终止 hasNext()为false。 最后,通过调用读取对象的右括号 endObject().
当遇到嵌套对象或数组时,委托给对应的处理方法。
当遇到未知名称时,严格的解析器应该失败并返回。 但宽松的解析器应该调用 skipValue()递归地 跳过值的嵌套标记,否则可能会发生冲突。
如果一个值可能为空,应该首先检查使用 peek(). 空字面量可以使用 nextNull()或者 skipValue().
例如,我之前要解析的json文件格式如下:
{"INFO": {"NAME": "","Result": "","Config": "",...},"ATTR": {"key01": "val01","key02": "val02",...},"Parms": [{"k": "","v": "","p": "","m": "","l": ""},{"k": "","v": "","p": "","m": "","l": ""},...],"List": ["xxx", "xxxx", ...]
}
那按照JsonReader解析的思路,我应该先消费整体对象的{,再逐个对INFO,ATTR,Parms,List进行处理,总而言之,就是
String fileName = "";
FileReader in = new FileReader(fileName);
JsonReader reader = new JsonReader(in);
reader.beginObject();
String rootName = null;
while (reader.hasNext()) {rootName = reader.nextName();if("INFO".equals(rootName)) {reader.beginObject();while (reader.hasNext()) {System.out.println(reader.nextName() + ":" + reader.nextString())}reader.endObject();}else if("ATTR".equals(rootName)) {reader.beginObject();while (reader.hasNext()) {System.out.println(reader.nextName() + ":" + reader.nextString())}reader.endObject();}else if("Parms".equals(rootName)) {reader.beginArray();while (reader.hasNext()) {reader.beginObject();String k = null;while (reader.hasNext()) {k = reader.nextName();switch (k) {case "k":xxx;break;case "v":xxx;break;case "p":xxx;break;case "m":xxx;break;case "l":xxx;break;default:reader.nextString();break;}}reader.endObject();}reader.endArray();}else if("List".equals(rootName)) {reader.beginArray();while (reader.hasNext()) {System.out.println(reader.nextString());}reader.endArray();}else {reader.skipValue();}
}
常用方法如下所示:
方法名 | 返回值 | 描述 |
---|---|---|
beginArray() | void | 使用JSON流中的下一个令牌,并断言它是新数组的开始。 |
endArray() | void | 使用JSON流中的下一个令牌,并断言它是当前数组的结尾。 |
beginObject() | void | 使用JSON流中的下一个令牌,并断言它是新对象的开始。 |
endObject() | void | 使用JSON流中的下一个令牌,并断言它是当前对象的结尾。 |
close() | void |
关闭此 JSON阅读器 和底层 Reader .
|
getPath() | String | 返回JSON值中当前位置的JsonPath。 |
hasNext() | Boolean | 如果当前数组或对象有其他元素,则返回true。 |
isLenient() | Boolean | 如果此解析器在接受的内容上是宽松的,则返回true。 |
setLenient(boolean lenient) | void | 将此解析器配置为在其接受的内容上宽松。 |
nextBoolean() | boolean | 返回boolean下一个令牌的值,并使用它。 |
nextDouble() | double | 返回double下一个令牌的值,并使用它。 |
nextInt() | int | 返回int下一个令牌的值,并使用它。 |
nextLong() | long | 返回long下一个令牌的值,并使用它。 |
nextName() | String | 返回下一个标记,即属性名,并使用它。 |
nextNull() | void | 使用JSON流中的下一个令牌,并断言它是文本null。 |
nextString() | String | 返回使用下一个标记的字符串值。 |
peek() | JsonToken | 返回下一个令牌的类型,而不使用它 |
skipValue() | void | 递归跳过下一个值。 |
通过使用JsonReader,现在我解析几十兆的文件基本没有问题(上百兆的还没尝试过),一个44.5M的JSON文件在4秒就能够处理完。
Java解析JSON大文件解决方案之JsonReader相关推荐
- 如何使用java解析json文件并将其写入数据库
JAVA解析JSON数据文件 在使用第三方的api文档时,会得到相应的JSON数据文件,那么我们怎样将JSON文件写入数据库从而测试数据呢?下面我将给大家做一个简单的展示. 一.什么是JSON JSO ...
- Python 获取接口数据,解析JSON,写入文件
Python 获取接口数据,解析JSON,写入文件 用于练手的例子,从国家气象局接口上获取JSON数据,将它写入文件中,并解析JSON: 总的来说,在代码量上,python代码量要比java少很多.而 ...
- Java高效读取大文件(转)
Java高效读取大文件 1.概述 本教程将演示如何用Java高效地读取大文件.这篇文章是Baeldung(http://www.baeldung.com/) 上"Java--回归基础&quo ...
- Java解析JSON出现双引号变成转义字符quot;解决办法
Java解析JSON出现双引号变成转义字符" 问题描述: 在接口中读取传过来的json数据,但是双引号都转义成了" 读取xml文件格式如下: {"message" ...
- asp.net core mvc上传大文件解决方案
asp.net core mvc上传大文件解决方案 参考文章: (1)asp.net core mvc上传大文件解决方案 (2)https://www.cnblogs.com/eggtwo/p/988 ...
- JavaScript 下载大文件解决方案(Blob+OjbectURL)
JavaScript 下载大文件解决方案(Blob+OjbectURL) 参考文章: (1)JavaScript 下载大文件解决方案(Blob+OjbectURL) (2)https://www.cn ...
- Php流式 大文件,如何使用PHP解析XML大文件
如果使用 PHP 解析 XML 的话,那么常见的选择有如下几种:DOM.SimpleXML.XMLReader.如果要解析 XML 大文件的话,那么首先要排除的是 DOM,因为使用 DOM 的话,需要 ...
- java解析json数组
java解析json数组 import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; p ...
- java解析json的一种方法
package com.hanchao.web; import net.sf.json.JSONArray; import net.sf.json.JSONObject; /************* ...
- Java解析JSON格式数据
Java解析JSON格式的数据主要用到两个类JSONObject和JSONArray,这两个类在json-lib-2.4-jdk15包中,在使用JSONObject时除了需要这个包外还需要相关的依赖包 ...
最新文章
- java2018笔试基础题_java基础笔试题
- Maya人物角色行走动画制作视频教程
- 编程开发之--单例模式(6)单元测试
- 计算机专业哪家强,计算机专业哪家强?这4所大学水平一流,网友:都是“大佬”级别...
- 移动办公计算机,最适合移动办公的三款掌上电脑点评
- linux编译器项目,编译器架构 LLVM
- java定时任务_ftp上传软件,ftp上传软件定时功能教程
- iOS 计步器的几种实现方式
- 【现代机器人学】名词概念的理解
- mysql执行程序_Sql在Mysql的执行
- error: ‘avcodec_alloc_frame’ was not declared in this scope
- 获取url路径上的参数,(避免中文乱码)
- 如何用php代码实现人脸识别,PHP实现人脸识别技术
- svm对未知数据的分类_SVM多分类之一对一与一对多
- SVM多分类器算法-一对多
- 计算机怎么演示音乐,做ppt的时候怎样添加音乐 想要在PPT里面增添视频以及音乐怎么操作...
- FinalShell SSH工具安装步骤及介绍
- 《编程之美》读书笔记(三):烙饼问题与搜索树
- React Native Text 组件显示不全解决方案
- sunny-ngrok linux命令,ngrok使用