【问题标题】:Reading multiple elements from json file从json文件中读取多个元素
【发布时间】:2012-06-28 21:53:55
【问题描述】:

我有一个包含许多元素的 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”异常。我该如何克服呢?

【问题讨论】:

  • JSON 意味着是一个单一的实体(可以是一个对象,或者一个数组)——而你得到的是多个对象。在这种情况下,您真正​​想要的是顶层的数组,每个对象都作为其中的一个元素。你会影响这个 JSON 的 生成,还是你被这种格式卡住了?

标签: java json file-io gson


【解决方案1】:

为了它的价值......

以下说法不正确。 Gson 没有内置功能来简单地处理此类 JSON 序列的反序列化。 (见 cmets。)

如果切换 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));
    }
  }
}

【讨论】:

  • 这篇文章不正确。 Gson 确实具有(错误)功能。它被称为 JsonStreamParser,文档在这里:google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/com/…
  • 啊,整洁。我被 GSON API 中“Stream”这个词的使用吓到了。我只是假设“Stream”指的是一次解析 JSON 一个流令牌,而不是将 JSON 数据绑定到对象/数组。
  • 这正是我想要的。当您想高效地将多个 JSON 节点写入文件时,它非常有用:您只需追加新元素,而不是解析数组、追加元素,然后将整个内容写回磁盘。
【解决方案2】:

Greg是对的,这是不正确的JSON,你应该尝试生成有效的JSON,即在开头添加“[”,在末尾添加“]”,每个元素用逗号(“,”隔开),因此它是 JSON 对象的 JSON 数组。

但是,如果您无法更改现有格式,请将其视为“包含格式良好的 JSON 片段串联的字符串”。以这种方式接近它,将大字符串分解成更小的、有效的 json 字符串,并一一解析。

要将大字符串分成单个片段,您可以简单地计算括号。使用“预解析器”将内容复制到缓冲区(StringBuilder?),每次遇到“{”时增加一个计数器,每次遇到“}”时减少它,如果计数器为零通过将缓冲区字符串传递给 gson 进行解析,清除缓冲区并继续到文件末尾。

您甚至可以使用该预解析器将其转换为有效的 json,只需在计数器达到零时附加一个“,”,然后将所有内容传递给 gson 进行一次解析,但这可能意味着将所有内容加载到 ram 中,我不知道你的文件有多大。

【讨论】:

  • 随之,您可以简单地将文件创建为 JSON 对象数组。但是,如果数组中的实体太多,您可能会遇到内存问题。否则,分开的 JSON 实体字符串会更好,并且一次只加载文件的一部分。
  • 是的,这就是我想要表达的:一个文件大的 json 数组和一个解析调用,看起来更容易,但也可能意味着将所有内容加载到 ram 中;在“一步一步”进行的同时,您能否让实体一个一个地处理……这又是针对 DOM 的 SAX,但现在它被称为 JSON,它听起来更像是 k00l。
  • 哈哈,真是的。尽管 JSON 看起来不那么冗长(例如没有结束标签),并且它还提供了一种非常简单的方法来将数据传递给 Javascript,这在当今风靡一时,因此可能是 JSON 大幅崛起的原因之一。
  • 是的,没有结束标签.. 非常好,只要您不必手动编辑 json 文件,或者具有非常非常简单的结构,但是当最后几行是 10s右括号? :D 如果我们只需要一种比 XML 更好的格式来进行机器对机器通信,那么 JSON 对于该任务来说甚至过于冗长了.. 但我认为我们偏离了主题 :D
  • 同意。无论如何,这都是关于 Avro 或 Thrift 的:P
猜你喜欢
  • 2013-03-22
  • 2012-07-23
  • 2016-08-18
  • 2017-06-26
  • 1970-01-01
  • 2020-12-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多