Análise JSON Incremental em C #

Eu estou tentando analisar o JSON incrementalmente, ou seja, com base em uma condição.

Abaixo está minha mensagem json e atualmente estou usando JavaScriptSerializer para desserializar a mensagem.

string json = @"{"id":2, "method":"add", "params": {"object": {"name":"test" "id":"1"}, "position":"1"} }"; JavaScriptSerializer js = new JavaScriptSerializer(); Message m = js.Deserialize(json); 

A class da mensagem é mostrada abaixo:

  public class Message { public string id { get; set; } public string method { get; set; } public Params @params { get; set; } public string position { get; set; } } public class Params { public string name { get; set; } public string id{ get; set; } 

O código acima analisa a mensagem sem problemas. Mas analisa todo o JSON de uma só vez. Eu quero que continue a análise apenas se o valor do parâmetro “method” for “add”. Se não for “adicionar”, não quero que continue a analisar o restante da mensagem. Existe uma maneira de fazer análise incremental com base em uma condição em c #? (Ambiente: VS 2008 com .Net 3.5)

Eu tenho que admitir que não sou tão familiarizado com o JavaScriptSerializer, mas se você está aberto para usar JSON.net , ele tem um JsonReader que age muito como um DataReader .

 using(var jsonReader = new JsonTextReader(myTextReader)){ while(jsonReader.Read()){ //evaluate the current node and whether it's the name you want if(jsonReader.TokenType.PropertyName=="add"){ //do what you want } else { //break out of loop. } } } 

Aqui estão os methods genéricos e simples que uso para analisar, carregar e criar arquivos JSON muito grandes. O código usa agora praticamente a biblioteca padrão JSON.Net . Infelizmente, a documentação não é muito clara sobre como fazer isso, mas não é muito difícil descobrir isso também.

O código abaixo assume o cenário em que você tem um grande número de objects que deseja serializar como matriz JSON e vice-versa. Queremos suportar arquivos muito grandes cujo tamanho é limitado apenas pelo seu dispositivo de armazenamento (não pela memory). Portanto, quando serializando, o método leva IEnumerable e ao desserializar retorna o mesmo. Desta forma, você pode processar o arquivo inteiro sem ser limitado pela memory.

Eu usei esse código em tamanhos de arquivo de vários GBs com desempenho razoável.

 //Serialize sequence of objects as JSON array in to a specified file public static void SerializeSequenceToJson(this IEnumerable sequence, string fileName) { using (var fileStream = File.CreateText(fileName)) SerializeSequenceToJson(sequence, fileStream); } //Deserialize specified file in to IEnumerable assuming it has array of JSON objects public static IEnumerable DeserializeSequenceFromJson(string fileName) { using (var fileStream = File.OpenText(fileName)) foreach (var responseJson in DeserializeSequenceFromJson(fileStream)) yield return responseJson; } //Utility methods to operate on streams instead of file public static void SerializeSequenceToJson(this IEnumerable sequence, TextWriter writeStream, Action progress = null) { using (var writer = new JsonTextWriter(writeStream)) { var serializer = new JsonSerializer(); writer.WriteStartArray(); long index = 0; foreach (var item in sequence) { if (progress != null) progress(item, index++); serializer.Serialize(writer, item); } writer.WriteEnd(); } } public static IEnumerable DeserializeSequenceFromJson(TextReader readerStream) { using (var reader = new JsonTextReader(readerStream)) { var serializer = new JsonSerializer(); if (!reader.Read() || reader.TokenType != JsonToken.StartArray) throw new Exception("Expected start of array in the deserialized json string"); while (reader.Read()) { if (reader.TokenType == JsonToken.EndArray) break; var item = serializer.Deserialize(reader); yield return item; } } } 

Se você der uma olhada no Json.NET , ele fornecerá um analisador JSON sem cache, apenas de encaminhamento, que atenderá às suas necessidades.

Veja a class JsonTextReader e JsonTextReader na documentação .

Atualmente, estou na hora 3 de um período de tempo desconhecido, vendo 160GB de JSON serem desserializados em objects de class. Meu uso de memory ficou bem apertado em ~ 350MB, e quando eu inspeciono os objects de memory, é tudo que o GC pode tomar cuidado. Aqui está o que eu fiz:

  FileStream fs = File.Open("F:\\Data\\mysuperbig150GB.json", FileMode.Open, FileAccess.Read, FileShare.ReadWrite); StreamReader sr = new StreamReader(fs); using (JsonReader reader = new JsonTextReader(sr)) { JsonSerializer serializer = new JsonSerializer(); MyJsonToClass result = serializer.Deserialize(reader); } 

O problema é a desserialização. Esses 160 GB de dados são muito maiores do que o meu PC pode lidar de uma só vez.

  1. Eu usei um pequeno trecho (que é difícil, mesmo abrindo um arquivo de 160GB) e ganhei uma estrutura de class via jsontochsarp .

  2. Fiz uma class específica para a grande coleção na estrutura de class auto-generated-via-json-tool e subclass System.Collection.ObjectModel.ObservableCollection em vez de List. Ambos implementam IEnumberable, o que eu acho que é tudo que o deserializador JSTS da Newtsonsoft se preocupa.

  3. Eu entrei e sobrei o InsertItem, assim:

     protected override void InsertItem(int index, Feature item) { //do something with the item that just got deserialized //stick it in a database, etc. RemoveItem(0); } 

Mais uma vez, meus problemas em que parcialmente a velocidade de desserialização do JSON, mas além disso, eu não conseguia caber ~ 160GB de dados JSON na coleção. Mesmo apertado, seria na área de dezenas de shows, muito maior do que a que a .net vai ficar feliz.

InsertItem on ObservableCollection é o único método que estou ciente de que você pode manipular quando ocorre a desserialização. List.Add () não. Eu sei que esta solução não é “elegante”, mas está funcionando enquanto digito isso.

Você estaria querendo um analisador do tipo SAX para JSON

http://en.wikipedia.org/wiki/Simple_API_for_XML

http://www.saxproject.org/event.html

O SAX gera um evento enquanto analisa cada parte do documento.

Fazer algo assim em JSON seria (deve) ser bem simples, dada a simplicidade da syntax do JSON.

Essa pergunta pode ajudar: há uma API de streaming para JSON?

E outro link: https://www.p6r.com/articles/2008/05/22/a-sax-like-parser-for-json/

Qual o motivo dessa abordagem? Se você se preocupa com o desempenho, é provável que haja uma “otimização prematura” ou, em outras palavras, preocupação com um problema que talvez não exista.

Eu recomendo fortemente que você não se preocupe com esse detalhe. Construa seu aplicativo e, se ele não for rápido o suficiente, use as ferramentas de criação de perfil para localizar os gargalos reais – eles provavelmente não estarão onde você espera.

Concentrar-se no desempenho antes de saber que é um problema quase sempre leva à perda de tempo e ao código excessivo.