使用java/GSON解析大型JSON,无法读取JSON结构

ki0zmccv  于 2022-11-06  发布在  Java
关注(0)|答案(2)|浏览(212)

我正在尝试使用Java和GSON解析www.example.com上的JSON格式的大型(大约10GB)数据库转储Musicbrainz.org
JSON文件是这样的结构。没有'[' ']'表示这将是一个对象数组,每个对象之间也没有','。不知道为什么,但这个JSON文件就是这样。

{
    "id": "d0ab06e1-751a-414b-a976-da72670391b1",
    "name": "Arcing Wires",
    "sort-name": "Arcing Wires"
}
{
    "id": "6f0c2c16-dd7e-4268-a484-bc7b2ac78108",
    "name": "Another",
    "sort-name": "Another"
}
{
    "id": "e062b6cd-5506-47b0-afdb-72f4279ec38c",
    "name": "Agent S",
    "sort-name": "Agent S"
}

这是我使用的代码:

try(JsonReader jsonReader = new JsonReader(
            new InputStreamReader(
                    new FileInputStream(jsonFilePath), StandardCharsets.UTF_8))) {
        Gson gson = new GsonBuilder().create();
        jsonReader.beginArray();
        while (jsonReader.hasNext()) {
            Artist mapped = gson.fromJson(jsonReader, Artist.class);
            //TODO do something with the object
            }
        }
        jsonReader.endArray();
    }
    catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

我Map的类是:

public class Artist {

@SerializedName("id")
public String id;
@SerializedName("name")
public String name;
@SerializedName("sort-name")
public String sortName;

}
我得到错误是:

Exception in thread "main" java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $
at com.google.gson.stream.JsonReader.beginArray(JsonReader.java:350)
at DBLoader.parse(DBLoader.java:39)
at DBLoader.main(DBLoader.java:23)

我相信GSON期望的结构与我声明的结构不同,但是我不明白我应该如何定义这种没有逗号和括号的JSON。

gk7wooem

gk7wooem1#

默认情况下,JSON只声明一个top值(是的,这将是一个 * 有效的JSON文档 *),但是有一种 JSON流 ,它使用任意技术将多个JSON元素连接到单个流中,假设流使用者可以解析它(read more). Gson支持所谓的宽松模式,该模式关闭“仅限一个最高值”模式(并做了一些与问题无关的事情)对于JsonReadersetLenient。打开宽松模式后,可以逐个读取JSON元素,结果表明,该模式可用于解析/读取 * 行分隔的JSON 和 * 连接的JSON值 ,因为它们仅由零个或多个空格分隔,而Gson会忽略这些空格(因此,不支持更奇特 * 记录分隔符分隔的JSON 和 * 长度前缀的JSON)。它不适用于您的原因是您的初始代码假定流包含单个JSON数组(显然它不包含:它应该是一个不符合JSON数组语法的元素流)。
一个简单的通用JSON流支持可能如下所示(使用Stream API,因为它比Iterator具有更丰富的API,但是展示一个想法是很好的,您可以轻松地将其调整为迭代器、回调、可观察流,无论您喜欢什么):

@UtilityClass
public final class JsonStreamSupport {

    public static <T> Stream<T> parse(@WillNotClose final JsonReader jsonReader, final Function<? super JsonReader, ? extends T> readElement) {
        final boolean isLenient = jsonReader.isLenient();
        jsonReader.setLenient(true);
        final Spliterator<T> spliterator = new Spliterators.AbstractSpliterator<T>(Long.MAX_VALUE, Spliterator.ORDERED) {
            @Override
            public boolean tryAdvance(final Consumer<? super T> action) {
                try {
                    final JsonToken token = jsonReader.peek();
                    if ( token == JsonToken.END_DOCUMENT ) {
                        return false;
                    }
                    // TODO: read more elements in batch
                    final T element = readElement.apply(jsonReader);
                    action.accept(element);
                    return true;
                } catch ( final IOException ex ) {
                    throw new RuntimeException(ex);
                }
            }
        };
        return StreamSupport.stream(spliterator, false)
                .onClose(() -> jsonReader.setLenient(isLenient));
    }

}

然后道:

JsonStreamSupport.<Artist>parse(jsonReader, jr -> gson.fromJson(jr, Artist.class))
        .forEach(System.out::println);

输出(假设Artist具有Lombok生成的toString()):
艺术家(id= d 0ab 06 e1 - 751 a-414 b-a976-da 72670391 b1,名称=电弧丝,类别名称=电弧丝)
艺术家(id= 6 f0 c2 c16-dd 7 e-4268-a484-bc 7 b2 ac 78108,名称=另一个,排序名称=另一个)
艺术家(id= e062 b6 cd-5506- 47 b 0-afdb-72 f4279 ec 38 c,名称=代理S,排序名称=代理S)
这种方法,JSON流,保存了多少字节,以便在您尝试使用的服务中使用?

zpf6vheq

zpf6vheq2#

它看起来像jsonl,其中每行都是一个有效的JSON对象。(阅读更多here
你可以逐行读取文件并转换为对象。我认为它会起作用的。

相关问题