用杰克逊流式传输大型JSON文件– RxJava常见问题解答
在上一篇文章中,我们学习了如何解析过大的XML文件并将其转换为RxJava流。 这次让我们看一个大的JSON文件。 我们的示例将基于微小的colors.json,其中包含将近150种这种格式的记录:
{"aliceblue": [240, 248, 255, 1],"antiquewhite": [250, 235, 215, 1],"aqua": [0, 255, 255, 1],"aquamarine": [127, 255, 212, 1],"azure": [240, 255, 255, 1],//...
鲜为人知的事实: 天蓝色也是一种颜色,而Python是蛇。 但是回到RxJava。 这个文件很小,但是我们将用它来学习一些原理。 如果遵循它们,您将能够加载和连续处理任意大,甚至无限长的JSON文件。 首先,标准的“ Jackson ”方式类似于JAXB:将整个文件加载到内存中并将其映射到Java bean。 但是,如果文件的大小为兆字节或千兆字节(由于某种原因,您发现JSON是存储千兆字节数据的最佳格式……),则此技术将无法使用。 幸运的是,杰克逊提供了类似于StAX的流模式。
使用Jackson逐个令牌加载JSON文件
使用JSON并将其转换为对象集合的标准ObjectMapper
没错。 但是为了避免将所有内容加载到内存中,我们必须使用下面的ObjectMapper
使用的较低级API。 让我们再次看一下JSON示例:
{"aliceblue": [240, 248, 255, 1],"antiquewhite": [250, 235, 215, 1],//...
从磁盘和内存的角度来看,这是一个单维字节流,我们可以在逻辑上将其聚合为JSON令牌:
START_OBJECT '{'
FIELD_NAME 'aliceblue'
START_ARRAY '['
VALUE_NUMBER_INT '240'
VALUE_NUMBER_INT '248'
VALUE_NUMBER_INT '255'
VALUE_NUMBER_INT '1'
END_ARRAY ']'
FIELD_NAME 'antiquewhite'
START_ARRAY '['
VALUE_NUMBER_INT '250'
VALUE_NUMBER_INT '235'
VALUE_NUMBER_INT '215'
VALUE_NUMBER_INT '1'
END_ARRAY ']'
...
你明白了。 如果您熟悉编译器理论,这是编译期间的第一步。 编译器将源代码从字符转换为令牌。
但是,如果您了解编译器理论,则可能不是为了生存而解析JSON。 无论如何! Jackson库以这种方式工作,我们可以在没有透明对象映射的情况下使用它:
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;JsonParser parser = new JsonFactory().createParser(new File("colors.json"));
parser.nextToken(); // JsonToken.START_OBJECT;
while (parser.nextToken() != JsonToken.END_OBJECT) {final String name = parser.getCurrentName();parser.nextToken(); // JsonToken.START_ARRAY;parser.nextValue();final int red = parser.getIntValue();parser.nextValue();final int green = parser.getIntValue();parser.nextValue();final int blue = parser.getIntValue();parser.nextValue();parser.getIntValue();System.out.println(name + ": " + red + ", " + green + ", " + blue);parser.nextToken(); // JsonToken.END_ARRAY;
}
parser.close();
…或者如果您摆脱了一些重复,并使代码更易于阅读:
import lombok.Value;JsonParser parser = new JsonFactory().createParser(new File("colors.json"));
parser.nextToken(); // JsonToken.START_OBJECT;
while (parser.nextToken() != JsonToken.END_OBJECT) {System.out.println(readColour(parser));
}
parser.close();//...private Colour readColour(JsonParser parser) throws IOException {final String name = parser.getCurrentName();parser.nextToken(); // JsonToken.START_ARRAY;final Colour colour = new Colour(name,readInt(parser),readInt(parser),readInt(parser),readInt(parser));parser.nextToken(); // JsonToken.END_ARRAY;return colour;
}private int readInt(JsonParser parser) throws IOException {parser.nextValue();return parser.getIntValue();
}@Value
class Colour {private final String name;private final int red;private final int green;private final int blue;private final int alpha;
}
它与RxJava有什么关系? 您可能会猜测–我们可以按需逐块读取此JSON文件。 这使背压机制可以无缝工作:
final Flowable colours = Flowable.generate(() -> parser(new File("colors.json")),this::pullOrComplete,JsonParser::close);
让我解释一下这三个lambda表达式在做什么。 第一个设置JsonParser
我们的可变状态,将用于产生( 拉动 )更多项目:
private JsonParser parser(File file) throws IOException {final JsonParser parser = new JsonFactory().createParser(file);parser.nextToken(); // JsonToken.START_OBJECT;return parser;
}
没有什么花哨。 第二个lambda表达式至关重要。 每当订户希望接收更多项目时,都会调用它。 如果它要求100个项目,则此lambda表达式将被调用100次:
private void pullOrComplete(JsonParser parser, Emitter<Colour> emitter) throws IOException {if (parser.nextToken() != JsonToken.END_OBJECT) {final Colour colour = readColour(parser);emitter.onNext(colour);} else {emitter.onComplete();}
}
当然,如果到达END_OBJECT
(关闭整个JSON文件),则表明流已结束。 最后一个lambda表达式仅允许清除状态,例如通过关闭JsonParser
和基础File
。 现在想象一下这个JSON文件的大小为数百GB。 有了Flowable<Colour>
我们可以以任意速度安全地使用它,而不会冒内存过载的风险。
翻译自: https://www.javacodegeeks.com/2017/09/streaming-large-json-file-jackson-rxjava-faq.html
用杰克逊流式传输大型JSON文件– RxJava常见问题解答相关推荐
- 迈克尔 杰克逊mv_用杰克逊流式传输大型JSON文件– RxJava常见问题解答
迈克尔 杰克逊mv 在上一篇文章中,我们学习了如何解析过大的XML文件并将其转换为RxJava流. 这次让我们看一个大的JSON文件. 我们的示例将基于微小的colors.json,其中包含将近150 ...
- Java 异步响应servlet_java – 使用jersey流式传输大型响应,异步
我想允许客户端(包括非常慢的客户端)从JAX-RS(泽西岛)Web服务下载大文件,我被卡住了.似乎JAX-RS中的异步胖子不支持这一点. >如果必须等待资源在服务器端可用,AsyncRespon ...
- mysql 结果集 超大_使用MySQL流式传输大型结果集
我正在开发一个使用大型MySQL表的spring应用程序.加载大表时,我得到一个OutOfMemoryException,因为驱动程序试图将整个表加载到应用程序内存中. 我尝试使用 statement ...
- OKHTTP 实现流式传输上传文件
1. 引入okhttp依赖 implementation 'com.squareup.okhttp3:okhttp:4.10.0' 2. 编写工具类 object HttpUtils {private ...
- grpc 流式传输_编写下载服务器。 第一部分:始终流式传输,永远不要完全保留在内存中...
grpc 流式传输 下载各种文件(文本或二进制文件)是每个企业应用程序的生死攸关的事情. PDF文档,附件,媒体,可执行文件,CSV,超大文件等.几乎每个应用程序迟早都必须提供某种形式的下载. 下载是 ...
- Java:将JDBC ResultSet作为JSON流式传输
这篇文章展示了如何将java.sql.ResultSet转换为JSON并将其流回调用方. 如果要将大型数据集从JDBC数据源以JSON格式发送到Web应用程序,此功能很有用. 流式传输使您可以一点一点 ...
- 读取csv文件 java_Java:逐步读取/流式传输CSV文件
读取csv文件 java 我一直在做一些涉及读取CSV文件的工作,而我一直在使用OpenCSV ,而我的最初方法是逐行读取文件,解析内容并将其保存到地图列表中. 当文件的内容适合内存时,此方法有效,但 ...
- Java:逐步读取/流式传输CSV文件
我一直在做一些涉及读取CSV文件的工作,而我一直在使用OpenCSV ,而我的最初方法是逐行读取文件,解析内容并将其保存到地图列表中. 当文件的内容适合内存时,此方法有效,但对于较大的文件来说是个问题 ...
- 从MongoDB GridFS流式传输文件
不久前,我在Twitter上发布了自己的最新作品,即从MongoDB GridFS传输文件进行下载(而不是将整个文件存储到内存中然后提供服务),这是我取得的一个小胜利. 我答应就此事写博客,但不幸的是 ...
最新文章
- 最小割 ---- 二分图最大独立集(集合冲突模型) ---- 骑士共存 方格取数(网络流24题)
- 省委书记表态:以“倾省之力”,支持中国科大建国际校区!
- html5可以用flash,HTML5网页可以直接看视频,不用flash吗,另外WP7为何不支持flash。。。HTML5网页...
- ssas 面试题_多维模型的SSAS面试问题
- [翻译] RAReorderableLayout
- 跟对人,走对路,做对事!
- java 删除文件或文件夹的7种方法(io基础)
- wireshark 安装失败报错,缺少kb2999226补丁的解决方案
- HTML的字体10种酷炫效果
- EDEM创建用于模拟颗粒工厂的多边形后,选中多边形视图中不显示红色多边形
- python上海房价数据分析_Python数据分析告诉你为何上海的二手房你都买不起
- 使用Vue指令实现下拉菜单效果
- 怎么合并mp3音频文件?
- java 时间计算差值
- 面部识别软件可以帮助女性找到看起来像他们的卵子捐赠者
- 无盘服务器接几根网线,设置无线路由器需要几根网线_安装路由器需要几根网线?-192路由网...
- r5 5600x性能 r5 5600x有核显吗
- [基础]-requests模块使用详解
- 很久未使用计算机会怎样,很久没用,电脑为什么不能启动?
- Vivado 2019.1安装包下载
热门文章
- eclipse搭建多module项目的坑
- 使用org.apache.commons.io.FileUtils,IOUtils工具类操作文件
- 聊聊并发(八)——Fork/Join框架介绍
- Oracle入门(十二B)之表创建
- Spring 思维导图,让 Spring 不再难懂(cache篇)
- Layui hint: Table element property lay-data configuration item has a syntax error解决方式
- Hibernate中使用Criteria查询及注解——( EmpCondition)
- 拦截器中/* vs /** ------SpringMVC
- 方舟非主机服务器无限距离,方舟非专业服务器距离限制怎么解除 | 手游网游页游攻略大全...
- (转) SpringBoot接入两套kafka集群