Deserialize o stream da matriz json, um item por vez

Eu serializo uma matriz de objects grandes para um stream de resposta http json. Agora quero desserializar esses objects do stream, um de cada vez. Há alguma biblioteca c # que me permita fazer isso? Eu olhei para json.net mas parece que eu teria que desserializar a matriz completa de objects de uma só vez.

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

Esclarecimento: Eu quero ler um object json do stream de cada vez e desserializá-lo.

Para ler o JSON incrementalmente, você precisará usar um JsonTextReader em combinação com um StreamReader . Mas você não precisa necessariamente ler todo o JSON manualmente do leitor. Você deve ser capaz de aproveitar a API Linq-To-JSON para carregar cada object grande do leitor, para que você possa trabalhar com ele mais facilmente.

Por exemplo, digamos que eu tenha um arquivo JSON assim:

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

Código para ler de forma incremental a partir do arquivo pode ser algo como o seguinte. (No seu caso, você replaceia o FileStream pelo stream de resposta.)

 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"]); } } } 

A saída do acima ficaria assim:

 1 - foo 2 - bar 3 - baz 

Eu simplifiquei uma das amostras / testes do meu analisador / desserializador para responder mais diretamente ao caso de uso desta questão.

Aqui está para os dados de teste:

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

(cf. fathers.json.txt)

E aqui está o código de amostra:

  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(); } 

O resto dos bits está disponível aqui:

https://github.com/ysharplanguage/FastJsonParser

‘HTH,

Esta é a minha solução (combinada de diferentes fonts, mas baseada principalmente na solução de Brian Rogers ) para converter arquivos JSON enormes (que são uma matriz de objects) em um arquivo XML para qualquer object genérico.

JSON parece com isso:

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

XML de saída:

 ... ... ... 

Código 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(""); }