[英]Deserializing large json from WebService using Json.NET
我从 WebService 接收到一个大的 JSON 字符串,我正在寻找最好的 memory 优化方法,使用 C# 对其进行反序列化。
JSON结构:
{
"d": {
"results": [
{
"metadata": {
"id": "",
"uri": "",
"type": ""
},
"ID": "",
"Value1": "",
"Value2": "",
"Value3": ""
},
{
"metadata": {
"id": "",
"uri": "",
"type": ""
},
"ID": "",
"Value1": "",
"Value2": "",
"Value3": ""
},
]
}
}
我想在“结果”数组中获取所有 object 但只有一个 object 一个接一个,而不像现在的完整列表。 我已经在使用 StreamReader 来避免将完整的 json 字符串加载到 memory 中。 是否有任何选项可以只读取一个 object,进行一些处理然后读取下一个以避免“OutOfMemoryExceptions”?
WebResponse response = r.GetResponse();
using (Stream dataStream = response.GetResponseStream())
{
var serializer = new JsonSerializer();
using (var sr = new StreamReader(dataStream))
using (var jsonTextReader = new JsonTextReader(sr))
{
return ((RootObject)serializer.Deserialize<RootObject>(jsonTextReader)).RootObject2.Results;
}
What you can do is to adopt the basic approach of Issues parsing a 1GB json file using JSON.NET and Deserialize json array stream one item at a time , which is to stream through the JSON and deserialize and yield return each object; 但另外应用一些状态过滤表达式来反序列化仅匹配路径d.results[*]
的StartObject
令牌。
为此,首先定义以下接口和扩展方法:
public interface IJsonReaderFilter
{
public bool ShouldDeserializeToken(JsonReader reader);
}
public static class JsonExtensions
{
public static IEnumerable<T> DeserializeSelectedTokens<T>(Stream stream, IJsonReaderFilter filter, JsonSerializerSettings settings = null, bool leaveOpen = false)
{
using (var sr = new StreamReader(stream, leaveOpen : leaveOpen))
using (var reader = new JsonTextReader(sr))
foreach (var item in DeserializeSelectedTokens<T>(reader, filter, settings))
yield return item;
}
public static IEnumerable<T> DeserializeSelectedTokens<T>(JsonReader reader, IJsonReaderFilter filter, JsonSerializerSettings settings = null)
{
var serializer = JsonSerializer.CreateDefault(settings);
while (reader.Read())
if (filter.ShouldDeserializeToken(reader))
yield return serializer.Deserialize<T>(reader);
}
}
现在,要仅过滤与路径d.results[*]
匹配的项目,请定义以下过滤器:
class ResultsFilter : IJsonReaderFilter
{
const string path = "d.results";
const int pathDepth = 2;
bool inArray = false;
public bool ShouldDeserializeToken(JsonReader reader)
{
if (!inArray && reader.Depth == pathDepth && reader.TokenType == JsonToken.StartArray && string.Equals(reader.Path, "d.results", StringComparison.OrdinalIgnoreCase))
{
inArray = true;
return false;
}
else if (inArray && reader.Depth == pathDepth + 1 && reader.TokenType == JsonToken.StartObject)
return true;
else if (inArray && reader.Depth == pathDepth && reader.TokenType == JsonToken.EndArray)
{
inArray = false;
return false;
}
else
{
return false;
}
}
}
接下来,为每个结果创建以下数据 model:
public class Metadata
{
public string id { get; set; }
public string uri { get; set; }
public string type { get; set; }
}
public class Result
{
public Metadata metadata { get; set; }
public string ID { get; set; }
public string Value1 { get; set; }
public string Value2 { get; set; }
public string Value3 { get; set; }
}
现在您可以逐步反序列化您的 JSON stream 如下:
foreach (var result in JsonExtensions.DeserializeSelectedTokens<Result>(dataStream, new ResultsFilter()))
{
// Process each result in some manner.
result.Dump();
}
演示小提琴在这里。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.