一尘不染

在.NET中解析大型JSON文件

c#

到目前为止,我已经使用了Json.NET的“ JsonConvert.Deserialize(json)”方法,该方法运行良好,说实话,我只需要这些。

我正在开发一个后台(控制台)应用程序,该应用程序不断从不同的URL下载JSON内容,然后将结果反序列化为.NET对象列表。

 using (WebClient client = new WebClient())
 {
      string json = client.DownloadString(stringUrl);

      var result = JsonConvert.DeserializeObject<List<Contact>>(json);

 }

上面的简单代码片段似乎并不完美,但确实可以做到。当文件很大(15,000个联系人-48
MB文件)时,JsonConvert.DeserializeObject不是解决方案,该行将引发JsonReaderException的异常类型。

下载的JSON内容是一个数组,这就是示例的样子。Contact是反序列化JSON对象的容器类。

[
  {
    "firstname": "sometext",
    "lastname": "sometext"
  },
  {
    "firstname": "sometext",
    "lastname": "sometext"
  },
  {
    "firstname": "sometext",
    "lastname": "sometext"
  },
  {
    "firstname": "sometext",
    "lastname": "sometext"
  }
]

我最初的猜测是它的内存不足。出于好奇,我试图将其解析为JArray,这也导致了相同的异常。

我已经开始深入研究Json.NET文档并阅读类似的主题。由于我尚未设法产生可行的解决方案,因此我决定在此处发布一个问题。

更新:在逐行反序列化时,我遇到了相同的错误:“ [。Path”,行600003,位置1。” 因此,下载了其中两个,并在Notepad
++中进行了检查。我注意到,如果数组长度超过12,000,则在第12000个元素之后,将关闭“ [”并启动另一个数组。换句话说,JSON看起来完全像这样:

[
  {
    "firstname": "sometext",
    "lastname": "sometext"
  },
  {
    "firstname": "sometext",
    "lastname": "sometext"
  },
  {
    "firstname": "sometext",
    "lastname": "sometext"
  },
  {
    "firstname": "sometext",
    "lastname": "sometext"
  }
]
[
  {
    "firstname": "sometext",
    "lastname": "sometext"
  },
  {
    "firstname": "sometext",
    "lastname": "sometext"
  },
  {
    "firstname": "sometext",
    "lastname": "sometext"
  },
  {
    "firstname": "sometext",
    "lastname": "sometext"
  }
]

阅读 705

收藏
2020-05-19

共1个答案

一尘不染

正如您在更新中正确诊断出的那样,问题在于JSON先关闭,]然后再打开[以开始下一个集合。这种格式使JSON整体上无效,这就是Json.NET引发错误的原因。

幸运的是,这个问题似乎经常出现,以至于Json.NET实际上具有处理它的特殊设置。如果JsonTextReader直接使用a
来读取JSON,则可以将SupportMultipleContent标志设置为true,然后使用循环分别反序列化每个项目。

这应该使您能够以内存有效的方式成功处理非标准JSON,而不管存在多少个数组或每个数组中有多少个项目。

    using (WebClient client = new WebClient())
    using (Stream stream = client.OpenRead(stringUrl))
    using (StreamReader streamReader = new StreamReader(stream))
    using (JsonTextReader reader = new JsonTextReader(streamReader))
    {
        reader.SupportMultipleContent = true;

        var serializer = new JsonSerializer();
        while (reader.Read())
        {
            if (reader.TokenType == JsonToken.StartObject)
            {
                Contact c = serializer.Deserialize<Contact>(reader);
                Console.WriteLine(c.FirstName + " " + c.LastName);
            }
        }
    }

完整的演示在这里:https :
//dotnetfiddle.net/2TQa8p

2020-05-19