2012-06-28 2 views
5

У меня есть файл в формате JSON с большим количеством элементов, как это:Чтение несколько элементов из файла JSON

{ 
"code" : "hfuiew89", 
"type" : "location", 
"coordinates" : [ { "lat" : 40.9861, "lon" : 29.1046, "index" : 1 }, 
      { "lat" : 40.9976, "lon" : 29.1153, "index" : 2 }, 
      { "lat" : 40.9809, "lon" : 29.2194, "index" : 3 }] 
} 
{ 
"code" : "klsdsjh", 
"type" : "location", 
"relatedTags" : [ "kolmha" ], 
"coordinates" : [ { "lat" : 40.9808, "lon" : 29.1605, "index" : 1 }, 
       { "lat" : 40.9965, "lon" : 29.1672, "index" : 2 }] 
} 

я хочу, чтобы прочитать этот файл с gson, но все примеры я нашел только для одного элемента. поэтому после прочтения первого, выбрасывает исключение «Ожидаемое EOF». как я могу это преодолеть?

+2

JSON является * * означает быть единым целым (будь то объект или массив) - и то, что у вас есть это несколько объектов. То, что вы действительно хотите в этой ситуации, - это массив на верхнем уровне, причем каждый объект является его элементом. Можете ли вы повлиять на * поколение * этого JSON, или вы застряли в этом формате? –

ответ

3

Greg прав, это неверно JSON, и вы должны попытаться сгенерировать действительный JSON, который добавляет «[» в начале, добавляет «]» в конце и разделяет каждый элемент запятой («, "), так что это массив JSON объекта JSON.

Однако, если вы не можете изменить формат, который у вас есть, считайте его «строкой, содержащей конкатенацию хорошо сформированных фрагментов JSON». Приближаясь к этому, разбивайте большую строку на более мелкие, правильные строки json и разбирайте их один за другим.

Чтобы разбить большую строку на отдельные фрагменты, вы можете просто подсчитать скобки. С «пред-парсером», который копирует материал в буфер (StringBuilder?), Увеличивает счетчик каждый раз, когда он встречает «{», уменьшает его каждый раз, когда он выдает «}», и если счетчик равен нулю буферную строку для gson для синтаксического анализа, очистить буфер и перейти к концу файла.

Вы можете использовать этот предварительный синтаксический анализатор, чтобы преобразовать его в действительный json, просто добавив «,», когда счетчик достигнет нуля, и передав все в gson для одного синтаксического анализа, но это может означать загрузку всего в ram , и я не знаю, насколько велик ваш файл.

+0

В этом случае вы можете просто создать свой файл в виде массива объектов JSON. Однако вы можете столкнуться с проблемами памяти, если в массиве слишком много объектов.В противном случае выделенная строка сущностей JSON будет лучше и позволит вам загружать только часть файла за раз. – Drizzt321

+0

Да, это то, что я пытался выразить: один массив большого размера json и один вызов для синтаксического анализа, может показаться проще, но также может означать загрузку всего в ram; в то время как «шаг за шагом» вы можете позволить обрабатывать объекты один за другим ... это SAX против DOM снова, но теперь, когда он называется JSON, он делает звук намного больше k00l. –

+0

Ха-ха, так верно. Хотя JSON действительно выглядит менее многословным (например, закрывающие теги), а также предоставляет очень легкое средство для передачи данных в Javascript, что в наши дни является яростью, и, возможно, это одна из причин большого роста JSON. – Drizzt321

9

Для чего это стоит ...

следующее утверждение неверно. Gson не имеет встроенной функции, чтобы просто обрабатывать десериализацию такой последовательности JSON. (См. Комментарии.)

Если опция JSON-to/from-Java API является опцией, то Jackson имеет такую ​​функцию, как показано ниже.

input.json

{ 
"name":"A" 
} 
{ 
"name":"B" 
} 

JacksonFoo.java

import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.ANY; 
import static com.fasterxml.jackson.annotation.PropertyAccessor.FIELD; 

import java.io.File; 
import java.util.Iterator; 

import com.fasterxml.jackson.databind.ObjectMapper; 

public class JacksonFoo 
{ 
    public static void main(String[] args) throws Exception 
    { 
    ObjectMapper mapper = new ObjectMapper().setVisibility(FIELD, ANY); 
    Iterator<Thing> thingsIterator = mapper.reader(Thing.class).readValues(new File("input.json")); 
    while (thingsIterator.hasNext()) 
    { 
     System.out.println(thingsIterator.next()); 
    } 
    } 
} 

class Thing 
{ 
    private String name; 

    @Override 
    public String toString() 
    { 
    return String.format("Thing: name=%s", name); 
    } 
} 

Выход:

Thing: name=A 
Thing: name=B 

Обновление: Аналогичное решение с использованием Gson.

GsonFoo.java

import java.io.FileReader; 

import com.google.gson.Gson; 
import com.google.gson.GsonBuilder; 
import com.google.gson.JsonStreamParser; 

public class GsonFoo 
{ 
    public static void main(String[] args) throws Exception 
    { 
    Gson gson = new GsonBuilder().create(); 

    JsonStreamParser parser = new JsonStreamParser(new FileReader("input.json")); 
    while(parser.hasNext()) 
    { 
     System.out.println(gson.fromJson(parser.next(), Thing.class)); 
    } 
    } 
} 
+2

Это сообщение неверно. У Gson есть эта (неправильная) функция. Это называется JsonStreamParser, и документация находится здесь: http://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/com/google/gson/JsonStreamParser.html –

+0

А, аккуратный. Меня бросила использование слова «Стрим» в API GSON. Я просто предположил, что «поток» относится к разбору одного потокового токена JSON за раз, в отличие от привязки данных JSON к объектам/массивам. –

+0

Обновленный ответ соответственно. –

Смежные вопросы