繁体   English   中英

使用 Json.NET 从 WebService 反序列化大型 json

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM