Can Json.NET serializacja / deserializacja do / ze strumienia?
Słyszałem, że Json.NET jest szybszy niż DataContractJsonSerializer i chciał spróbować...
Ale nie mogłem znaleźć żadnych metod na JsonConvert, które pobierają strumień, a nie ciąg.
Do deserializacji pliku zawierającego JSON na WinPhone, na przykład, używam poniższego kodu, aby odczytać zawartość pliku do ciągu znaków, a następnie deserializować do JSON. Wydaje się być około 4 razy wolniejszy w moich (bardzo ad-hoc) testach niż przy użyciu DataContractJsonSerializer do deserializuj prosto ze strumienia...
// 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<Constants>(json);
Czy robię to źle?
Dzięki,
Omri.5 answers
UPDATE: to już nie działa w obecnej wersji, zobacz poniżej dla poprawnej odpowiedzi ( nie trzeba głosować w dół, to jest poprawne w starszych wersjach ).
Użyj klasy JsonTextReader
z StreamReader
lub użyj przeciążenia JsonSerializer
, które zabiera StreamReader
bezpośrednio:
var serializer = new JsonSerializer();
serializer.Deserialize(streamReader);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:38
Aktualna wersja Json.net nie pozwala na użycie zaakceptowanego kodu odpowiedzi. Aktualna alternatywa to:
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);
}
}
Dokumentacja: Deserializacja JSON ze strumienia plików
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-30 20:35:31
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<T>(Stream s)
{
using (StreamReader reader = new StreamReader(s))
using (JsonTextReader jsonReader = new JsonTextReader(reader))
{
JsonSerializer ser = new JsonSerializer();
return ser.Deserialize<T>(jsonReader);
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-04 17:37:20
Napisałem klasę rozszerzenia, która pomoże mi deserializować ze źródeł JSON (string, stream, file).
public static class JsonHelpers
{
public static T CreateFromJsonStream<T>(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<T>(this String json)
{
T data;
using (MemoryStream stream = new MemoryStream(System.Text.Encoding.Default.GetBytes(json)))
{
data = CreateFromJsonStream<T>(stream);
}
return data;
}
public static T CreateFromJsonFile<T>(this String fileName)
{
T data;
using (FileStream fileStream = new FileStream(fileName, FileMode.Open))
{
data = CreateFromJsonStream<T>(fileStream);
}
return data;
}
}
Deserializacja jest teraz tak łatwa jak pisanie:
MyType obj1 = aStream.CreateFromJsonStream<MyType>();
MyType obj2 = "{\"key\":\"value\"}".CreateFromJsonString<MyType>();
MyType obj3 = "data.json".CreateFromJsonFile<MyType>();
Mam nadzieję, że to pomoże komuś innemu.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-29 13:42:10
Przyszedłem na to pytanie, szukając sposobu na strumieniowe przesyłanie otwartej listy obiektów na {[1] } i odczytywanie ich z drugiego końca, bez buforowania całej listy przed wysłaniem. (Konkretnie przesyłam strumieniowo obiekty z MongoDB przez Web API.)
@ Paul Tyng i @ Rivers wykonali świetną robotę odpowiadając na oryginalne pytanie, a ja użyłem ich odpowiedzi, aby zbudować dowód koncepcji dla mojego problemu. Postanowiłem opublikować tutaj moją testową aplikację konsolową na wypadek, gdyby ktoś inny stanął w obliczu ten sam problem.
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<DataItem>(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);
}
}
}
}
Zauważ, że możesz otrzymać wyjątek, gdy AnonymousPipeServerStream
jest usuwany, zignorowałem to, ponieważ nie jest to istotne dla danego problemu.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-24 22:39:16