Json.NET 可以序列化/反序列化到/来自流吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8157636/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 16:02:39  来源:igfitidea点击:

Can Json.NET serialize / deserialize to / from a stream?

.netserializationjson.net

提问by Omri Gazitt

I have heard that Json.NET is faster than DataContractJsonSerializer, and wanted to give it a try...

我听说 Json.NET 比 DataContractJsonSerializer 快,我想试一试......

But I couldn't find any methods on JsonConvert that take a stream rather than a string.

但是我在 JsonConvert 上找不到任何采用流而不是字符串的方法。

For deserializing a file containing JSON on WinPhone, for example, I use the following code to read the file contents into a string, and then deserialize into JSON. It appears to be about 4 times slower in my (very ad-hoc) testing than using DataContractJsonSerializer to deserialize straight from the stream...

例如,在 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);

Am I doing it wrong?

我做错了吗?

采纳答案by Paul Tyng

UPDATE:This no longer works in the current version, see belowfor correct answer (no need to vote down, this is correct on older versions).

更新:这不再适用于当前版本,请参阅下面的正确答案(无需投票,这在旧版本上是正确的)。

Use the JsonTextReaderclass with a StreamReaderor use the JsonSerializeroverload that takes a StreamReaderdirectly:

使用JsonTextReader带有 a的类StreamReader或使用直接JsonSerializer采用 a的重载StreamReader

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

回答by

The current version of Json.net does not allow you to use the accepted answer code. A current alternative is:

当前版本的 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);
    }
}

Documentation: Deserialize JSON from a file stream

文档:从文件流中反序列化 JSON

回答by ygaradon

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

回答by Tok'

I've written an extension class to help me deserializing from JSON sources (string, stream, file).

我编写了一个扩展类来帮助我从 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;
    }
}

Deserializing is now as easy as writing:

反序列化现在就像编写一样简单:

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

Hope it will help someone else.

希望它会帮助别人。

回答by Blake Mitchell

I arrived at this question looking for a way to stream an open ended list of objects onto a System.IO.Streamand read them off the other end, without buffering the entire list before sending. (Specifically I'm streaming persisted objects from MongoDB over Web API.)

我遇到了这个问题,寻找一种方法将对象的开放式列表流式传输到 aSystem.IO.Stream并从另一端读取它们,而无需在发送之前缓冲整个列表。(具体来说,我通过 Web API 从 MongoDB 流式传输持久对象。)

@Paul Tyng and @Rivers did an excellent job answering the original question, and I used their answers to build a proof of concept for my problem. I decided to post my test console app here in case anyone else is facing the same issue.

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

Note that you may receive an exception when the AnonymousPipeServerStreamis disposed, I ignored this as it isn't relevant to the problem at hand.

请注意,您可能会在处理时收到异常AnonymousPipeServerStream,我忽略了这一点,因为它与手头的问题无关。