Разбор большого json-файла в .NET.

Я использовал метод JsonConvert.Deserialize (json) Json.Net до сих пор, который работал достаточно хорошо, и, честно говоря, мне не нужно ничего больше, чем это.

Я работаю над фоновым (консольным) приложением, которое постоянно загружает содержимое json из разных URL-адресов, а затем десериализует результат в список .Net-объекта.

using (WebClient client = new WebClient()) { string json = client.DownloadString(stringUrl); var result = JsonConvert.DeserializeObject<List>(json); } 

Простой fragment кода выше, вероятно, не кажется идеальным, но он выполняет эту работу. Когда файл большой (15000 контактов – 48 МБ файла), JsonConvert.DeserializeObject не является решением, а строка генерирует исключение типа JsonReaderException.

Загруженный json – это массив, и вот как выглядит образец. Contact – это контейнерный class для десериализованного json-объекта.

 [ { "firstname": "sometext", "lastname": "sometext" }, { "firstname": "sometext", "lastname": "sometext" }, { "firstname": "sometext", "lastname": "sometext" }, { "firstname": "sometext", "lastname": "sometext" } ] 

Моя первоначальная догадка заключается в том, что у нее заканчивается память. Просто из любопытства я попытался разобрать его как JArray, который также вызвал одно и то же исключение.

Я начал погружаться в документацию Json.Net и читать похожие темы. Поскольку я еще не успел создать рабочее решение, я решил задать вопрос здесь.

Я был бы признателен за любой совет / fragment кода, который мог бы помочь мне в исследовании проблемы, узнав больше об этом и в конечном итоге добравшись до решения.

Благодаря 🙂

ОБНОВЛЕНИЕ: при десериализации строки за строкой я получил ту же ошибку: «[путь», строка 600003, позиция 1. » Так что я сделал это, чтобы загрузить два из них и проверить их в Notepad ++. Я заметил, что если длина массива больше 12000, то после 12000-го элемента «[» закрывается и начинается другой массив. Другими словами, json выглядит так:

 [ { "firstname": "sometext", "lastname": "sometext" }, { "firstname": "sometext", "lastname": "sometext" }, { "firstname": "sometext", "lastname": "sometext" }, { "firstname": "sometext", "lastname": "sometext" } ] [ { "firstname": "sometext", "lastname": "sometext" }, { "firstname": "sometext", "lastname": "sometext" }, { "firstname": "sometext", "lastname": "sometext" }, { "firstname": "sometext", "lastname": "sometext" } ] 

Поскольку вы правильно поставили диагноз в своем обновлении, проблема заключается в том, что JSON имеет закрытие ] сразу же после открытия [ для запуска следующего набора. Этот формат делает JSON недействительным, когда он взят в целом, и именно поэтому Json.Net выдает ошибку. К счастью, эта проблема, похоже, достаточно часто возникает, что у Json.Net действительно есть специальная настройка для решения этой проблемы. Если вы используете JsonTextReader непосредственно для чтения JSON, вы можете установить флаг SupportMultipleContent true , а затем использовать цикл для десериализации каждого элемента отдельно. Это должно позволить вам обрабатывать нестандартные JSON успешно и эффективно, независимо от количества массивов или количества элементов в каждом массиве.

  using (WebClient client = new WebClient()) using (Stream stream = client.OpenRead(stringUrl)) using (StreamReader streamReader = new StreamReader(stream)) using (JsonTextReader reader = new JsonTextReader(streamReader)) { reader.SupportMultipleContent = true; var serializer = new JsonSerializer(); while (reader.Read()) { if (reader.TokenType == JsonToken.StartObject) { Contact c = serializer.Deserialize(reader); Console.WriteLine(c.FirstName + " " + c.LastName); } } } 

Полная демонстрация здесь: https://dotnetfiddle.net/2TQa8p

Json.NET поддерживает десериализацию непосредственно из streamа. Вот способ десериализации JSON с использованием StreamReader читает строку JSON за один раз за раз, вместо того, чтобы загружать всю строку JSON в память.

 using (WebClient client = new WebClient()) { using (StreamReader sr = new StreamReader(client.OpenRead(stringUrl))) { using (JsonReader reader = new JsonTextReader(sr)) { JsonSerializer serializer = new JsonSerializer(); // read the json from a stream // json size doesn't matter because only a small piece is read at a time from the HTTP request IList result = serializer.Deserialize>(reader); } } } 

Ссылка: Советы по производительности JSON.NET

Я сделал аналогичную вещь в python для размера файла 5 ГБ. Я загрузил файл в некотором временном месте и прочитал его по очереди, чтобы сформировать объект JSON, похожий на то, как работает SAX. Для c # с помощью json.net вы можете скачать файл, использовать считыватель streamа для чтения файла и передать этот stream JsonTextReader и разобрать его на JObject, используя JTokens.ReadFrom (ваш объект JSonTextReader)

  • Как использовать JSON.NET для десериализации в вложенный / рекурсивный словарь и список?
  • Как я могу разбирать JSON с C #?
  • Json.NET Отключить десериализацию в DateTime
  • Дессериализация данных JSON на C # с использованием JSON.NET
  • VB.net JSON Deserialize
  • Newtonsoft JSON Deserialize
  • Сериализация Java - java.io.InvalidClassException локальный class несовместим
  • Json.NET: десериализация вложенных словарей
  • Как сериализовать объект, который включает BufferedImages
  • Удаление десериализации JSON в .NET-объект с использованием Newtonsoft (или LINQ to JSON, возможно?)
  • Давайте будем гением компьютера.