Json.NET이 DataContractJsonSerializer보다 빠르다는 것을 들었고 시도해보고 싶었습니다 …
그러나 JsonConvert에서 문자열 대신 스트림을 사용하는 메소드를 찾을 수 없습니다.
예를 들어, WinPhone에서 JSON을 포함하는 파일을 직렬화 해제하려면 다음 코드를 사용하여 파일 내용을 문자열로 읽은 다음 JSON으로 직렬화 해제하십시오. 스트림에서 직렬화를 해제하기 위해 DataContractJsonSerializer를 사용하는 것보다 (아주 임시) 테스트에서 약 4 배 더 느린 것으로 보입니다 …
// 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);
내가 잘못하고 있습니까?
답변
업데이트 : 이것은 현재 버전에서 더 이상 작동하지 않습니다. 정답 은 아래 를 참조하십시오 ( 투표 할 필요가 없으며 이전 버전에서는 정확합니다 ).
사용 JsonTextReader
로모그래퍼 클래스를 StreamReader
하거나 사용 JsonSerializer
걸리는 과부하 StreamReader
직접 :
var serializer = new JsonSerializer();
serializer.Deserialize(streamReader);
답변
Json.net의 현재 버전에서는 허용되는 응답 코드를 사용할 수 없습니다. 현재 대안은 다음과 같습니다.
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);
}
}
설명서 : 파일 스트림에서 JSON 직렬화 해제
답변
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);
}
}
답변
JSON 소스 (문자열, 스트림, 파일)에서 직렬화를 해제하는 데 도움이되는 확장 클래스를 작성했습니다.
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;
}
}
역 직렬화는 이제 쓰기만큼 쉽습니다.
MyType obj1 = aStream.CreateFromJsonStream<MyType>();
MyType obj2 = "{\"key\":\"value\"}".CreateFromJsonString<MyType>();
MyType obj3 = "data.json".CreateFromJsonFile<MyType>();
그것이 다른 누군가를 도울 수 있기를 바랍니다.
답변
나는이 질문에 도달하여 열린 끝의 객체 목록을 스트리밍하는 방법을 찾고 System.IO.Stream
보내기 전에 전체 목록을 버퍼링하지 않고 하여 다른 쪽 끝에서 읽을 수 . (특히 MongoDB에서 웹 API를 통해 지속 객체를 스트리밍하고 있습니다.)
@Paul Tyng과 @Rivers는 원래 질문에 대답하는 데 훌륭한 역할을했으며 내 대답에 대한 개념 증명을 작성하기 위해 답을 사용했습니다. 다른 사람이 같은 문제에 직면 한 경우 여기에 테스트 콘솔 앱을 게시하기로 결정했습니다.
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);
}
}
}
}
AnonymousPipeServerStream
이 처리 될 때 예외가 발생할 수 있습니다 . 현재 문제와 관련이 없으므로 무시했습니다.