如何在Json.NET中将巨大的JSON文件解析为流?

我有一个非常非常大的JSON文件(1000+ MB)相同的JSON对象。 例如:

[ { "id": 1, "value": "hello", "another_value": "world", "value_obj": { "name": "obj1" }, "value_list": [ 1, 2, 3 ] }, { "id": 2, "value": "foo", "another_value": "bar", "value_obj": { "name": "obj2" }, "value_list": [ 4, 5, 6 ] }, { "id": 3, "value": "a", "another_value": "b", "value_obj": { "name": "obj3" }, "value_list": [ 7, 8, 9 ] }, ... ] 

根JSON列表中的每个项都遵循相同的结构,因此可以单独反序列化。 我已经编写了C#类来接收这些数据,并且反序列化包含单个对象的JSON文件而没有列表按预期工作。

起初,我试图在循环中直接反序列化我的对象:

 JsonSerializer serializer = new JsonSerializer(); MyObject o; using (FileStream s = File.Open("bigfile.json", FileMode.Open)) using (StreamReader sr = new StreamReader(s)) using (JsonReader reader = new JsonTextReader(sr)) { while (!sr.EndOfStream) { o = serializer.Deserialize(reader); } } 

这不起作用,提出了一个例外,明确指出一个对象是预期的,而不是列表。 我的理解是这个命令只读取包含在JSON文件根级别的单个对象,但由于我们有一个对象列表 ,这是一个无效的请求。

我的下一个想法是反序列化为C#对象列表:

 JsonSerializer serializer = new JsonSerializer(); List o; using (FileStream s = File.Open("bigfile.json", FileMode.Open)) using (StreamReader sr = new StreamReader(s)) using (JsonReader reader = new JsonTextReader(sr)) { while (!sr.EndOfStream) { o = serializer.Deserialize<List>(reader); } } 

这确实成功了。 但是,它只是在一定程度上减少了高RAM使用率的问题。 在这种情况下,它看起来像应用程序一次一个地反序列化项目,因此不是将整个JSON文件读入RAM,但我们最终仍然有大量的RAM使用,因为C#List对象现在包含所有的来自RAM中JSON文件的数据。 这只能解决问题。

然后我决定简单地尝试从流的开头取一个字符(通过在进入循环之前执行sr.Read()来消除[ )。 然后第一个对象成功读取,但后续的对象没有,但“意外令牌”除外。 我的猜测是这是抛出阅读器的物体之间的逗号和空格。

简单地删除方括号将不起作用,因为对象确实包含它们自己的原始列表,如示例中所示。 即使尝试使用},作为分隔符将无法工作,因为您可以看到,对象中有子对象。

我的目标是能够一次一个地从流中读取对象。 读取一个对象,用它做一些事情,然后从RAM中丢弃它,然后读取下一个对象,依此类推。 这样就不需要将整个JSON字符串或数据的全部内容作为C#对象加载到RAM中。

我错过了什么?

这应该可以解决您的问题。 基本上它就像你的初始代码一样工作,除了它只是当读者点击流中的{字符时反序列化对象,否则它只是跳到下一个,直到找到另一个起始对象令牌。

 JsonSerializer serializer = new JsonSerializer(); MyObject o; using (FileStream s = File.Open("bigfile.json", FileMode.Open)) using (StreamReader sr = new StreamReader(s)) using (JsonReader reader = new JsonTextReader(sr)) { while (reader.Read()) { // deserialize only when there's "{" character in the stream if (reader.TokenType == JsonToken.StartObject) { o = serializer.Deserialize(reader); } } } 

这是你在找什么? 找到上一个问题

当前版本的Json.net不允许您使用接受的答案代码。 目前的替代方案是:

 public static object DeserializeFromStream(Stream stream) { var serializer = new JsonSerializer(); using (var sr = new StreamReader(stream)) using (var jsonTextReader = new JsonTextReader(sr)) { return serializer.Deserialize(jsonTextReader); } } 

文档: 从文件流中反序列化JSON