Gson: Как пропустить строки в массиве JSON при разборе с использованием потокового API
Пытаюсь разобрать огромный JSON
использование массива Gson stream
где для каждого прогона мне просто нужно обрабатывать 10 объектов одновременно.
Так что при первом запуске он обрабатывает 10. При втором запуске он начинается с 11-го. В-третьих, это начинается с 21-го и так далее... Вы получаете упражнение.
JSON-массив имеет формат:
[
{ "key1": "value1"},
{ "key2": "value2"},
{ "key3": "value3"},
{ "key4": "value4"},
..........
.........
..........
{ "key10": "value10"},
..........
.........
..........
{ "key20": "value20"},
..........
.........
..........
]
Я пытаюсь ниже код, но кажется, что он не работает должным образом и анализ всегда с самого начала. Это то, что я делаю:
public static void readJsonStream(int skipRows) {
JsonReader reader = null;
String FILENAME = "/examples/uh_data.json";
final InputStream stream = UHReportParser.class.getClass().getResourceAsStream(FILENAME);
try {
reader = new JsonReader(new InputStreamReader(stream, "UTF-8"));
Gson gson = new GsonBuilder().create();
// Read file in stream mode
reader.beginArray();
int count = 1;
while (reader.hasNext()) {
if (count++<=skipRows){
continue;
} else if(count>skipRows+10){
break;
}
else{
UserData data = null;
// Read data into object model
data = gson.fromJson(reader, UserData.class); //starts from one again
String description = data.getDescription();
}
}
} catch (UnsupportedEncodingException ex) {
ex.printStackTrace();
} catch (IOException ex) {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
Что следует изменить здесь? Как я могу достичь желаемых результатов?
1 ответ
Я не анализировал ваш алгоритм подробно, но он не пропускает значения на этапе "пропуска", и я определенно реорганизовал бы ваш читатель потока JSON, чтобы сделать его максимально чистым (по крайней мере, для того, что я могу) делать). Это позволит вам максимально использовать такой метод. Рассмотрим следующие методы:
static void readArrayBySkipAndLimitFromBegin(final JsonReader jsonReader, final int skip, final int limit,
final Consumer<? super JsonReader> callback)
throws IOException {
readArrayBySkipAndLimit(jsonReader, skip, limit, true, false, callback);
}
static void readArrayBySkipAndLimit(final JsonReader jsonReader, final int skip, final int limit, final boolean processBegin,
final boolean processEnd, final Consumer<? super JsonReader> callback)
throws IOException {
// the JSON stream can be already processed somehow
if ( processBegin ) {
jsonReader.beginArray();
}
// just skip the `skip`
for ( int i = 0; i < skip && jsonReader.hasNext(); i++ ) {
jsonReader.skipValue();
}
// and limit to the `limit` just passing the JsonReader instance to its consumer elsewhere
for ( int i = 0; i < limit && jsonReader.hasNext(); i++ ) {
callback.accept(jsonReader);
}
// in case you need it ever...
if ( processEnd ) {
while ( jsonReader.hasNext() ) {
jsonReader.skipValue();
}
jsonReader.endArray();
}
}
Вот документ JSON, который я использовал для его тестирования (всего 32 элемента массива):
[
{"key1": "value1"},
{"key2": "value2"},
...
{"key31": "value31"},
{"key32": "value32"}
]
Теперь проверьте это:
private static final Gson gson = new Gson();
private static final Type mapOfStringToStringType = new TypeToken<Map<String, String>>() {}.getType();
public static void main(final String... args)
throws IOException {
// read up to 2B+ entries, every 10 rows
for ( int i = 0; i >= 0; i += 10 ) {
System.out.print("Step #" + i / 10 + ": ");
final Collection<Map<String, String>> maps = new ArrayList<>();
// consume and close
try ( final JsonReader jsonReader = Resources.getPackageResourceJsonReader(Q50737654.class, "array.json") ) {
// consume the JSON reader, parse each array page element and add it to the result collection
readArrayBySkipAndLimitFromBegin(jsonReader, i, 10, jr -> maps.add(gson.fromJson(jr, mapOfStringToStringType)));
}
System.out.println(maps);
if ( maps.isEmpty() ) {
break;
}
}
System.out.println("Done");
}
Пример вывода:
Step #0: [{key1=value1}, {key2=value2}, {key3=value3}, {key4=value4}, {key5=value5}, {key6=value6}, {key7=value7}, {key8=value8}, {key9=value9}, {key10=value10}]
Step #1: [{key11=value11}, {key12=value12}, {key13=value13}, {key14=value14}, {key15=value15}, {key16=value16}, {key17=value17}, {key18=value18}, {key19=value19}, {key20=value20}]
Step #2: [{key21=value21}, {key22=value22}, {key23=value23}, {key24=value24}, {key25=value25}, {key26=value26}, {key27=value27}, {key28=value28}, {key29=value29}, {key30=value30}]
Step #3: [{key31=value31}, {key32=value32}]
Step #4: []
Done
Как видите, это действительно легко.