gpt4 book ai didi

java - 使用 Jackson 流式传输内部 JSONArray 记录,避免内存收集

转载 作者:行者123 更新时间:2023-12-01 18:18:47 25 4
gpt4 key购买 nike

最近尝试深入研究如何通过 HTTP 端点传输 JSON 内容,因为我不想在发送响应之前将整个 JSON 存储在内存中。

但是,我对如何执行此操作以及是否必须更改我之前的 JSON 架构以应对流式传输和稍后的解析有一些疑问。

目前我所拥有的(并且仍然希望进行流媒体)如下。

    {
"content": [ // I don't want to wait for this array to be populated to flush it.
{
"key": "value",
"yet": "another_value"
}, // read individual nested record, flush it
{
"key": "valueagain",
"yet": "another_value_in_here"
} // read individual nested record, flush it
],
"random": {
"more": "fields",
"in": {
"here": "yeah"
}
}
}

我的疑问是,有没有一种方法(使用 Jackson 或任何其他 Java 库)来流式传输 JSON 的内部部分,而无需等待关闭给定键的值?

假设我想开始流式传输

{ 
"content": [
...

然后是接下来的所有内容...

{
"key": "value",
"yet": "another_value"
}

或者这样做的方法是将整体结果更改为这样。

[
{
"key": "value",
"yet": "another_value"
},
{
"key": "valueagain",
"yet": "another_value_in_here"
},
{
"more": "fields",
"in": {
"here": "yeah"
}
}
]

那么,基本上,拥有一个 JsonGenerator,我是否能够刷新不完整的数组,例如我的示例中的数组?

jGenerator.writeStartObject();
jGenerator.writeFieldName("content");
jGenerator.writeStartArray();
jGenerator.flush(); // initial stream, records incoming within next flush. Can this be streamed?

jGenerator.writeStartObject();
jGenerator.writeStringField("key", "value");
jGenerator.writeStringField("yet", "another_value");
jGenerator.writeEndObject();
jGenerator.flush(); // streaming individual JSON object

... so on so forth until array is complete ...

jGenerator.writeEndArray();
jsonGenerator.writeFieldName("random");

最佳答案

如果您可以获取 Json 的输入流,而无需将整个内容放入内存中。例如,您可以将其保存在 HDD 上,然后从 File 获取 InputStream

有了 Jackson,你可以得到这样的东西:

  private final JsonParser jp;

public JsonArrayInputStreamWrapper(InputStream inputStream) throws IOException {
this.jp = new JsonFactory().createParser(inputStream);
setUpCursorToContentArray();
}

private void setUpCursorToContentArray() throws IOException {
// validate if json contains "content" key
do {
if (jp.nextToken() == null)
throw new JsonException("Provided input doesn't contain content.");
} while (!"content".equals(jp.getText()));

// set up coursor on first array that is found after "content"
while (jp.nextToken() != JsonToken.START_ARRAY) {
if (jp.currentToken() == null)
// throw exception when there weren't any array
throw new JsonException("Content input is malformed.");
}
}

所以我的想法是在我想要在这个所谓的包装器的构造函数中开始处理的地方设置我的游标。这样,在成功初始化对象后,我可以使用 hasNext()next() 进行更改。

  @Override
public boolean hasNext() {
if(jp.isClosed()) {
// has to be handled
}
return jp.nextToken() == JsonToken.START_OBJECT
}

@Override
public Map next() {
// where mapper is jackson ObjectMapper
return mapper.readValue(jp, Map.class);
}

这可以如下使用:

while (wrapper.hasNext()) {
var inv = wrapper.next();
//processing
}

完成处理后,不要忘记jp.close()

关于java - 使用 Jackson 流式传输内部 JSONArray 记录,避免内存收集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60316503/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com