如何分析不反序列化JSON整个文件只特定的对象?

时间:2019-02-02 16:30:49

标签: c# json json.net json-deserialization

我有一个巨大的JSON文件(成千上万个对象,> 100 MB文件),我试图对其进行解析以提取特定的对象。由于该文件是这么大,我想只反序列化特定的一部分,我需要(如果可能的话,那是),而无需反序列化整个文件。

所述目的,应根据特定属性的值"arena_id":xxxxx包含在每个对象中发现,被格式化这样的对象(精简版):

{"object":"card","id":"61a908e8-6952-46c0-94ec-3962b7a4caef","oracle_id":"e70f5520-1b9c-4351-8484-30f0dc692e01","multiverse_ids":[460007],"mtgo_id":71000,"arena_id":69421}

为了反序列化整个文件,我编写了以下代码:

public static RootObject GetCardFromBulkScryfall()
    {
        string s = null;

        using (StreamReader streamReader = new StreamReader(Path.Combine(GetAppDataPath(), @"scryfall-default-cards.json")))
        {
            s = streamReader.ReadToEnd();
        }

            RootObject card = JsonConvert.DeserializeObject<RootObject>(s);


        return card;
    }

我什至不确定我要做什么,但是如果不是我的问题,那么处理这样大的文件而不必对整个文件进行反序列化的最佳方法是什么?

2 个答案:

答案 0 :(得分:3)

使用JsonTextReaderJsonTextWriter枚举对象然后他们反序列化,如果他们的财产一直需要值。

此代码占用16MB内存,并在我的PC上使用112MB JSON文件。

让我知道,如果你有问题或需要修复。

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                string jsonFilePath = "1.json";

                string propName = "arena_id";

                RootObject[] objects = SearchObjectsWithProperty<RootObject, int>(jsonFilePath, propName, 69421, CancellationToken.None).ToArray();

                System.Diagnostics.Debugger.Break();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                System.Diagnostics.Debugger.Break();
            }
        }

        static IEnumerable<T> SearchObjectsWithProperty<T, V>(string jsonFilePath, string propName, V propValue, CancellationToken cancellationToken) where V : IEquatable<V>
        {
            using (TextReader tr = File.OpenText(jsonFilePath))
            {
                using (JsonTextReader jr = new JsonTextReader(tr))
                {
                    StringBuilder currentObjectJson = new StringBuilder();

                    while (jr.Read())
                    {
                        cancellationToken.ThrowIfCancellationRequested();                        

                        if (jr.TokenType == JsonToken.StartObject)
                        {
                            currentObjectJson.Clear();

                            using (TextWriter tw = new StringWriter(currentObjectJson))
                            {
                                using (JsonTextWriter jw = new JsonTextWriter(tw))
                                {
                                    jw.WriteToken(jr);

                                    string currObjJson = currentObjectJson.ToString();

                                    JObject obj = JObject.Parse(currObjJson);

                                    if (obj[propName].ToObject<V>().Equals(propValue))
                                        yield return obj.ToObject<T>();
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    public class RootObject
    {
        public string @object { get; set; }
        public string id { get; set; }
        public string oracle_id { get; set; }
        public int[] multiverse_ids { get; set; }
        public int mtgo_id { get; set; }
        public int arena_id { get; set; }
    }
}

答案 1 :(得分:0)

如果您不在乎内存,而是在乎速度,那么有一个快速简单的解析器可以从C ++转换为我的第一个问题的答案,但它具有像树一样的输出,除了打印和调试/浏览外,它缺少任何功能。对象(VisualNode3)。

Way to read (or edit) big JSON from / to stream