Уничтожить stream массива json по одному элементу за раз

Я сериализую массив больших объектов в stream ответов json http. Теперь я хочу десериализовать эти объекты из streamа по одному. Существуют ли библиотеки c #, которые позволят мне это сделать? Я посмотрел на json.net, но, похоже, мне пришлось бы десериализовать полный массив объектов сразу.

[{large json object},{large json object}.....] 

Уточнение: я хочу прочитать один объект json из streamа за раз и десериализировать его.

Чтобы постепенно считывать JSON, вам необходимо использовать JsonTextReader в сочетании с StreamReader . Но вам не обязательно читать все JSON вручную от читателя. Вы должны иметь возможность использовать Linq-To-JSON API для загрузки каждого большого объекта из считывателя, чтобы вы могли работать с ним более легко.

Для простого примера, скажем, у меня был JSON-файл, который выглядел так:

 [ { "name": "foo", "id": 1 }, { "name": "bar", "id": 2 }, { "name": "baz", "id": 3 } ] 

Код для его постепенного чтения из файла может выглядеть примерно так: (В вашем случае вы замените FileStream своим streamом ответов.)

 using (FileStream fs = new FileStream(@"C:\temp\data.json", FileMode.Open, FileAccess.Read)) using (StreamReader sr = new StreamReader(fs)) using (JsonTextReader reader = new JsonTextReader(sr)) { while (reader.Read()) { if (reader.TokenType == JsonToken.StartObject) { // Load each object from the stream and do something with it JObject obj = JObject.Load(reader); Console.WriteLine(obj["id"] + " - " + obj["name"]); } } } 

Результат выше будет выглядеть так:

 1 - foo 2 - bar 3 - baz 

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

Вот для тестовых данных:

https://github.com/ysharplanguage/FastJsonParser/tree/master/JsonTest/TestData

(см. fathers.json.txt)

И вот пример кода:

  using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; // Our stuff using System.Text.Json; //... public class FathersData { public Father[] fathers { get; set; } } public class Someone { public string name { get; set; } } public class Father : Someone { public int id { get; set; } public bool married { get; set; } // Lists... public List sons { get; set; } // ... or arrays for collections, that's fine: public Daughter[] daughters { get; set; } } public class Child : Someone { public int age { get; set; } } public class Son : Child { } public class Daughter : Child { public string maidenName { get; set; } } //... static void FilteredFatherStreamTestSimplified() { // Get our parser: var parser = new JsonParser(); // (Note this will be invoked thanks to the "filters" dictionary below) Func filteredFatherStreamCallback = obj => { Father father = (obj as Father); // Output only the individual fathers that the filters decided to keep (ie, when obj.Type equals typeof(Father)), // but don't output (even once) the resulting array (ie, when obj.Type equals typeof(Father[])): if (father != null) { Console.WriteLine("\t\tId : {0}\t\tName : {1}", father.id, father.name); } // Do not project the filtered data in any specific way otherwise, // just return it deserialized as-is: return obj; }; // Prepare our filter, and thus: // 1) we want only the last five (5) fathers (array index in the resulting "Father[]" >= 29,995), // (assuming we somehow have prior knowledge that the total count is 30,000) // and for each of them, // 2) we're interested in deserializing them with only their "id" and "name" properties var filters = new Dictionary>> { // We don't care about anything but these 2 properties: { typeof(Father), // Note the type (type, obj, key, index) => ((key as string) == "id" || (key as string) == "name") ? filteredFatherStreamCallback : JsonParser.Skip }, // We want to pick only the last 5 fathers from the source: { typeof(Father[]), // Note the type (type, obj, key, index) => (index >= 29995) ? filteredFatherStreamCallback : JsonParser.Skip } }; // Read, parse, and deserialize fathers.json.txt in a streamed fashion, // and using the above filters, along with the callback we've set up: using (var reader = new System.IO.StreamReader(FATHERS_TEST_FILE_PATH)) { FathersData data = parser.Parse(reader, filters); System.Diagnostics.Debug.Assert ( (data != null) && (data.fathers != null) && (data.fathers.Length == 5) ); foreach (var i in Enumerable.Range(29995, 5)) System.Diagnostics.Debug.Assert ( (data.fathers[i - 29995].id == i) && !String.IsNullOrEmpty(data.fathers[i - 29995].name) ); } Console.ReadKey(); } 

Остальные биты доступны здесь:

https://github.com/ysharplanguage/FastJsonParser

«НТН,

Это мое решение (объединенное из разных источников, но в основном основанное на решении Брайана Роджерса ) для преобразования огромного файла JSON (который представляет собой массив объектов) в XML-файл для любого общего объекта.

JSON выглядит так:

  { "Order": [ { order object 1}, { order object 2}, {...} { order object 10000}, ] } 

Выходной XML:

 ... ... ... 

Код C #:

 XmlWriterSettings xws = new XmlWriterSettings { OmitXmlDeclaration = true }; using (StreamWriter sw = new StreamWriter(xmlFile)) using (FileStream fs = new FileStream(jsonFile, FileMode.Open, FileAccess.Read)) using (StreamReader sr = new StreamReader(fs)) using (JsonTextReader reader = new JsonTextReader(sr)) { //sw.Write(""); while (reader.Read()) { if (reader.TokenType == JsonToken.StartArray) { while (reader.Read()) { if (reader.TokenType == JsonToken.StartObject) { JObject obj = JObject.Load(reader); XmlDocument doc = JsonConvert.DeserializeXmlNode(obj.ToString(), "Order"); sw.Write(doc.InnerXml); // a line of XML code ... sw.Write("\n"); //this approach produces not strictly valid XML document //add root element at the beginning and at the end to make it valid XML } } } } //sw.Write(""); } 
  • ASP.Net MVC - чтение файла из HttpPostedFileBase без сохранения
  • Как клонировать InputStream?
  • Как закрыть читаемый stream (до конца)?
  • endl и очистка буфера
  • Получение массива байтов из Windows :: Storage :: Streams :: IBuffer
  • Должен ли я вызвать Close () или Dispose () для объектов streamа?
  • ReadAllLines для объекта Stream?
  • Закрытие streamов в Java
  • Значение buffer_size в Dataset.map, Dataset.prefetch и Dataset.shuffle
  • Создание входного streamа из постоянной памяти
  • Как превратить String в InputStreamReader в java?
  • Давайте будем гением компьютера.