O Json.NET pode serializar / desserializar para / de um stream?

Ouvi dizer que o Json.NET é mais rápido que o DataContractJsonSerializer e queria tentar …

Mas não consegui encontrar nenhum método no JsonConvert que use um stream em vez de uma cadeia.

Para desserializar um arquivo contendo JSON no WinPhone, por exemplo, eu uso o seguinte código para ler o conteúdo do arquivo em uma seqüência de caracteres e, em seguida, desserializá-lo em JSON. Parece ser cerca de 4 vezes mais lento no meu teste (muito ad-hoc) do que usar DataContractJsonSerializer para desserializar diretamente do stream …

// DCJS DataContractJsonSerializer dc = new DataContractJsonSerializer(typeof(Constants)); Constants constants = (Constants)dc.ReadObject(stream); // JSON.NET string json = new StreamReader(stream).ReadToEnd(); Constants constants = JsonConvert.DeserializeObject(json); 

Estou fazendo errado?

Obrigado,

Omri

    ATUALIZAÇÃO: Isso não funciona mais na versão atual, veja abaixo a resposta correta ( não é necessário votar, isso está correto em versões mais antigas ).

    Use a class JsonTextReader com um StreamReader ou use a sobrecarga do JsonSerializer que usa diretamente um StreamReader :

     var serializer = new JsonSerializer(); serializer.Deserialize(streamReader); 

    A versão atual do Json.net não permite que você use o código de resposta aceito. Uma alternativa atual é:

     public static object DeserializeFromStream(Stream stream) { var serializer = new JsonSerializer(); using (var sr = new StreamReader(stream)) using (var jsonTextReader = new JsonTextReader(sr)) { return serializer.Deserialize(jsonTextReader); } } 

    Documentação: Deserializar JSON de um stream de arquivos

     public static void Serialize(object value, Stream s) { using (StreamWriter writer = new StreamWriter(s)) using (JsonTextWriter jsonWriter = new JsonTextWriter(writer)) { JsonSerializer ser = new JsonSerializer(); ser.Serialize(jsonWriter, value); jsonWriter.Flush(); } } public static T Deserialize(Stream s) { using (StreamReader reader = new StreamReader(s)) using (JsonTextReader jsonReader = new JsonTextReader(reader)) { JsonSerializer ser = new JsonSerializer(); return ser.Deserialize(jsonReader); } } 

    Eu escrevi uma class de extensão para me ajudar a desserializar de fonts JSON (string, stream, file).

     public static class JsonHelpers { public static T CreateFromJsonStream(this Stream stream) { JsonSerializer serializer = new JsonSerializer(); T data; using (StreamReader streamReader = new StreamReader(stream)) { data = (T)serializer.Deserialize(streamReader, typeof(T)); } return data; } public static T CreateFromJsonString(this String json) { T data; using (MemoryStream stream = new MemoryStream(System.Text.Encoding.Default.GetBytes(json))) { data = CreateFromJsonStream(stream); } return data; } public static T CreateFromJsonFile(this String fileName) { T data; using (FileStream fileStream = new FileStream(fileName, FileMode.Open)) { data = CreateFromJsonStream(fileStream); } return data; } } 

    A desserialização é agora tão fácil quanto escrever:

     MyType obj1 = aStream.CreateFromJsonStream(); MyType obj2 = "{\"key\":\"value\"}".CreateFromJsonString(); MyType obj3 = "data.json".CreateFromJsonFile(); 

    Espero que ajude alguém.

    Cheguei a essa questão procurando uma maneira de transmitir uma lista aberta de objects para um System.IO.Stream e lê-los do outro lado, sem armazenar toda a lista antes de enviá-los. (Especificamente, estou transmitindo objects persistentes do MongoDB pela API da Web.)

    @Paul Tyng e @Rivers fizeram um excelente trabalho respondendo a pergunta original, e eu usei suas respostas para construir uma prova de conceito para o meu problema. Decidi postar meu aplicativo de console de teste aqui, caso alguém esteja enfrentando o mesmo problema.

     using System; using System.Diagnostics; using System.IO; using System.IO.Pipes; using System.Threading; using System.Threading.Tasks; using Newtonsoft.Json; namespace TestJsonStream { class Program { static void Main(string[] args) { using(var writeStream = new AnonymousPipeServerStream(PipeDirection.Out, HandleInheritability.None)) { string pipeHandle = writeStream.GetClientHandleAsString(); var writeTask = Task.Run(() => { using(var sw = new StreamWriter(writeStream)) using(var writer = new JsonTextWriter(sw)) { var ser = new JsonSerializer(); writer.WriteStartArray(); for(int i = 0; i < 25; i++) { ser.Serialize(writer, new DataItem { Item = i }); writer.Flush(); Thread.Sleep(500); } writer.WriteEnd(); writer.Flush(); } }); var readTask = Task.Run(() => { var sw = new Stopwatch(); sw.Start(); using(var readStream = new AnonymousPipeClientStream(pipeHandle)) using(var sr = new StreamReader(readStream)) using(var reader = new JsonTextReader(sr)) { var ser = new JsonSerializer(); if(!reader.Read() || reader.TokenType != JsonToken.StartArray) { throw new Exception("Expected start of array"); } while(reader.Read()) { if(reader.TokenType == JsonToken.EndArray) break; var item = ser.Deserialize(reader); Console.WriteLine("[{0}] Received item: {1}", sw.Elapsed, item); } } }); Task.WaitAll(writeTask, readTask); writeStream.DisposeLocalCopyOfClientHandle(); } } class DataItem { public int Item { get; set; } public override string ToString() { return string.Format("{{ Item = {0} }}", Item); } } } } 

    Observe que você pode receber uma exceção quando o AnonymousPipeServerStream é descartado, eu ignorei isso como não é relevante para o problema em questão.