javascript
用杰克逊流式传输大型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 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常见问题解答的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 神武2官网手游电脑版下载安装(神武手游官
- 下一篇: 电脑版本远程协助软件(电脑版本远程协助软