用杰克逊流式传输大型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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/349062.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python多级目录import_你真的会用Python模块与工具包吗?

在开发过程中&#xff0c;我们无法把所有代码、资源都放在同一个文件中。因此&#xff0c;模块导入在编码中是很常见的。无论是C、Java&#xff0c;还是Python、Go。可以把不同功能、不同模块进行分离&#xff0c;当使用的时候&#xff0c;可以通过import关键字在一个模块中使用…

八边形点坐标数的lisp_图形学入门第五课:齐次坐标

齐次坐标(Homegeneous Coordinates)在学习齐次坐标之前&#xff0c;我们要先好奇的问一下&#xff0c;为什么要学习齐次坐标。上一节课&#xff0c;我们学习了变换的三种基本形式&#xff1a;旋转&#xff0c;缩放&#xff0c;和切变。但是还有一种特殊的变换&#xff1a;Trans…

spring java配置_Spring Java配置

spring java配置我发现许多我认识的Spring开发人员仍然不了解或使用Spring Java Configuration&#xff08;aka JavaConfig&#xff09;。 Spring 3.0引入了此功能&#xff0c;该功能使Spring可以完全用Java进行配置-不再需要XML&#xff01; 我真的很喜欢使用JavaConfig&#…

分段概率密度矩估计_考研数学:高数、线代、概率3科目知识框架梳理

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼首先要确保常考题型&#xff0c;常考知识点非常熟练。下面从高等数学、线性代数、概率统计三个模块进行阐述。高等数学部分1.函数的极 限;数列的极 限;无穷小及阶的问题;2.微分中值定理的证明;不等式的证明;方程根的存在性及个数问…

对速度的需求,访问现有数据的速度提高了1000倍

了解如何通过使用标准Java 8流和Speedment的In-JVM-Memory加速器将分析数据库应用程序加速1000倍。 Web和移动应用程序有时会很慢&#xff0c;因为后备数据库很慢和/或与数据库的连接施加了延迟。 现代UI和交互式应用程序需要快速后端&#xff0c;并且理想情况下没有可观察到的…

mysqls压力测试怎么用_用 Swagger 测试接口,怎么在请求头中携带 Token?

松哥周末抽空给 Spring Security 系列也录制了一套视频&#xff0c;目录如下&#xff1a;感兴趣的小伙伴戳这里-->Spring BootVue微人事视频教程今天的话题来自一个小伙伴在微信上的提问&#xff1a;看到这个问题&#xff0c;松哥忽然想到我自己之前写过 Spring BootSwagger…

disruptor3_发布Disruptor 3.0.0

disruptor3我决定对整个版本的Disruptor都放置一个beta标签感到无聊&#xff0c;所以我决定将Disruptor 3.0.0发行到全世界。 此版本的最大挑战是清理代码并提出更好的算法来处理多个生产者。 如果我很幸运&#xff0c;可以更快。 在发布此版本时&#xff0c;我最初走了几个阴暗…

安卓手机背景变黑色怎么改_别着急扔掉旧手机 你的电脑可能需要它

PC玩家中&#xff0c;不少人都会有在玩游戏时观测电脑硬件状态的习惯。比如查看游戏帧数、CPU频率、GPU频率或是温度等。大多数人都是通过第三方软件&#xff0c;在游戏内把监测数据显示到电脑显示屏角落。可就算是在角落&#xff0c;这些数据依旧会阻挡游戏画面&#xff0c;在…

JDeps入门–分析项目的依赖关系

JDeps是Java依赖关系分析工具 &#xff0c;这是一个命令行工具&#xff0c;它处理Java字节码&#xff08;意味着.class文件或包含它们的JAR&#xff09;&#xff0c;并分析类之间静态声明的依赖关系。 可以用各种方式过滤结果&#xff0c;并可以将其汇总到包或JAR级别。 JDeps还…

禅道开源版用户手册_Docker搭建开源版禅道以及项目基本流程介绍

对于自学软件测试的同学来说&#xff0c;经常会遇到这样的困惑&#xff1a;测试用例怎么写&#xff1f;有啥好的模板&#xff1f;缺陷提交的模板是什么样的&#xff1f;bug的生命周期是啥&#xff1f;项目的流程是啥&#xff1f;以上这些困惑&#xff0c;在你仔细看完这篇文章后…

f12 卡 谷歌浏览器_抢券第二课:利用浏览器F12获取优惠券请求链接

抢券第二课为什么迟迟不来呢&#xff1f;因为最近京东没有那种神券需要定点抢购的&#xff0c;我也没法测试我的理论。现在京东的券随时可以领取到&#xff0c;我多没法测试的东西不想就这样欺骗你们。所以今天的第二课我们讲一讲神奇的谷歌浏览器F1201 工具准备一、浏览器这里…

Java命令行界面(第5部分):JewelCli

细算在Java命令行处理与Apache的百科全书CLI &#xff0c; args4j &#xff0c; jbock和命令行中先前的文章&#xff0c;我把注意力转向在这个岗位使用JewelCli完成的命令行参数相似的处理Java中。 几个Java命令行处理库使用批注来定义命令行选项。 到目前为止&#xff0c;本系…

dnf用虚拟机会被制裁吗_DNF: 神豪奶妈扬言, 战斗力没有超过他的, 都不配被加buff!...

要说到现在的年轻人们的交友方式绝对少不了游戏交友&#xff0c;以前的人们只要不出门那就是与世隔绝&#xff0c;而现在就算是不出门也可以在网络上结交一大帮朋友&#xff0c;游戏就是现在的年轻人们交友最多的地方之一。科技的发展让游戏进入了一个繁荣的春天&#xff0c;不…

什么叫轻量瓷_为什么说陶瓷是华夏文明的徽章?

一、先说何为徽章&#xff1f;徽&#xff0c;最基本的解释是标志、符号&#xff1b;章&#xff0c;基本释义较多&#xff0c;其之一为佩戴在身上的标志&#xff0c;如领章、胸章等。徽章&#xff0c;也就是佩戴在身上用以表示身份、职业或者荣誉的标志。徽章的作用是明确身份、…

Java命令行界面(第10部分):picocli

picocli主页面将picocli描述为“强大的微小命令行界面”&#xff0c;“ picocli”是一个文件Java框架&#xff0c;用于解析命令行参数并生成精美&#xff0c;易于定制的用法帮助消息。 有颜色。” 这篇文章简要介绍了如何使用Picocli 0.9.7处理Java代码中的命令行参数。 像本系…

workunit 的指的工作单元是什么_分频器是做什么用的?

由于现在的音箱几乎都采用多单元分频段重放的设计方式&#xff0c;所以必须有一种装置&#xff0c;能够将功放送来的全频带音乐信号按需要划分为高音、低音输出或者高音、中音、低音输出&#xff0c;才能跟相应的喇叭单元连接&#xff0c;分频器就是这样的装置。如果把全频带信…

合并不同gdb下的相同要素_GDB调试学习

简介GDB是GCC的调试工具。其功能如下&#xff1a;启动程序&#xff0c;使程序按自定义形式运行&#xff1b;使程序停止指定断点位置&#xff1b;程序停止后&#xff0c;检查程序执行中的相应情况&#xff1b;动态改变程序执行环境。gdb调试能进行GDB调试&#xff0c;一般在编译…

SpringHibernate3

1.概述 本文将重点介绍通过Spring设置Hibernate 3 –我们将研究如何同时使用XML和Java配置通过Hibernate 3和MySQL设置Spring 3。 2. Hibernate 3的Java Spring配置 使用Spring和Java配置来设置Hibernate 3很简单&#xff1a; import java.util.Properties; import javax.sql…

endnote文献顺序编号不对_把Endnote装进大脑:行走的文献管理者

是否还迷失在茫茫的文献海洋&#xff0c;东翻西找&#xff0c;仍无法获得需要的文献信息&#xff1f;是否还在半手动导入参考文献&#xff0c;费时费力&#xff1f;别着急&#xff0c;文献管理神器-Endnote轻松帮你搞定这些问题。把Endnote“装进”大脑&#xff0c;你就能成为行…

Jersey Web Service Hello World Java示例

在Restlet之后&#xff0c; Jersey是另一个流行的开源框架&#xff0c;可以用Java创建RESTful Web服务 。 Jersey符合JAX-RS规范&#xff0c;实际上它是JAX-RS&#xff08;JSR 311&#xff09;&#xff08;http://jsr311.java.net/nonav/releases/1.1/index.html&#xff09;规…