在.NET中parsing大的json文件

我已经使用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); } 

上面的简单代码片段可能看起来并不完美,但是它完成了这项工作。 当文件较大时(15000个联系人 – 48 MB文件),JsonConvert.DeserializeObject不是解决scheme,并且该行引发JsonReaderException的exceptiontypes。

下载的json是一个数组,这是一个样本的样子。 Contact是反序列化的json对象的容器类。

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

我最初的猜测是内存耗尽。 出于好奇,我试图把它parsing为JArray,这也造成了同样的例外。

我已经开始深入Json.Net文档并阅读类似的线程。 由于我还没有设法解决问题,所以我决定在这里发表一个问题。

我会很感激任何意见/代码片段,可以帮助我研究这个问题,了解更多的信息并最终得到一个解决scheme。

谢谢 :)

更新:而逐行反序列化,我得到了同样的错误:“[。path”,行600003,位置1。 所以我所做的就是下载其中的两个,并在Notepad ++中检查它们。 我注意到,如果数组长度超过12000,在第12000个元素之后,“[”被closures,另一个数组开始。 换句话说,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" } ] 

正如您在更新中正确诊断出的那样,问题是JSON有一个结束]然后立即开始[开始下一个集合。 这种格式使JSON无效,这就是为什么Json.Net引发错误。 幸运的是,这个问题似乎经常出现,Json.Net实际上有一个特殊的设置来处理它。 如果您直接使用JsonTextReader读取JSON,则可以将SupportMultipleContent标志设置为true ,然后使用循环对每个项目单独进行反序列化。 这应该允许您以一种有效的内存方式成功地处理非标准的JSON,而不pipe有多less个数组部分或每个数组中有多less个项目。

  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

Json.NET支持直接从stream中进行反序列化。 这是一种使用StreamReader反序列化JSON的方法,一次只读一个JSONstring,而不是将整个JSONstring加载到内存中。

 using (WebClient client = new WebClient()) { using (StreamReader sr = new StreamReader(client.OpenRead(stringUrl))) { using (JsonReader reader = new JsonTextReader(sr)) { JsonSerializer serializer = new JsonSerializer(); // read the json from a stream // json size doesn't matter because only a small piece is read at a time from the HTTP request IList<Contact> result = serializer.Deserialize<List<Contact>>(reader); } } } 

参考: JSON.NET性能提示

我已经在5 GB的文件大小的python做类似的事情。 我在一些临时的位置下载了这个文件,然后逐行阅读,形成一个与SAX工作方式类似的JSON对象。 对于使用json.net的c#,您可以下载文件,使用stream读取器读取文件,并将该stream传递给JsonTextReader并使用JTokens.ReadFrom(您的JSonTextReader对象)将其parsing为JObject。