Как анализировать только определенные объекты без десериализации всего файла JSON? - PullRequest
0 голосов
/ 02 февраля 2019

У меня огромный JSON-файл (десятки тысяч объектов, файл> 100 МБ), который я пытаюсь проанализировать, чтобы извлечь конкретные объекты.Поскольку файл такой большой, я пытаюсь десериализовать только нужную мне часть (если это возможно) без необходимости десериализации всего файла.

Указанный объект должен быть найден на основе значенияопределенного свойства "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 голосов
/ 15 мая 2019

В случае, если вам не важна память, но скорость, есть быстрый и простой парсер, переведенный с C ++ как ответ на мой 1-й вопрос, но он имеет древовидную структуру и в нем отсутствуют какие-либо функции, кроме печати и отладки / просмотраобъект (VisualNode3).

Способ чтения (или редактирования) большого JSON из / в поток

0 голосов
/ 02 февраля 2019

Используйте JsonTextReader с JsonTextWriter , чтобы перечислять объекты, а затем десериализовать их, если их свойство имеет необходимое значение.

Этот код занимает 16 МБ памяти, работая с файлом JSON 112 МБ на моем ПК.

Дайте мне знать, если у вас есть вопросы или вам нужны исправления.

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; }
    }
}
...