我不喜欢在流接口之间使用MemoryStream对象。它们很笨拙,要求您重新开始寻找,并且在苛刻的情况下也会使内存使用达到峰值。
有时,实用程序只能以某种方式工作。也许它会输出byte [],或写入流,或者是您读取的管道中的流,从中拉出数据。
这个Newtonsoft JSON序列化程序是一个只能写入流的实用程序。
var js = new Newtonsoft.Json.JsonSerializer();
var sw = new StreamWriter(ps);
js.Serialize(sw, o);
这对我来说是一个问题,因为我想链接:
除了让JSON反序列化器呈现一个漂亮的IEnumerable接口的困难之外,其余部分不提供适合流水线操作的接口。即使是GZIP压缩方面也是错误的。
理想情况下,在服务器端我可以这样做:
IEnumerable<object> o = GetData();
var js = new Newtonsoft.Json.JsonSerialization(o);
var gz = new System.IO.Compression.GZipStream(js, System.IO.Compression.CompressionMode.Compress, true);
return new FileStreamResult(gz, "application/x-gzip");
我可以扩展Newtonsoft项目以提供管道实现,我可以这样做。但在那之前我需要一个解决方案,我相信其他实用程序(包括BCL GZipStream)需要一个解决方案。
我正在研究这样一个图书馆,不要指望有这样的图书馆。
答案 0 :(得分:0)
答案是全新的StreamAdaptor项目: https://bitbucket.org/merarischroeder/alivate-stream-adaptor。它仍然需要一些工作 - 将它打包为NuGet包会很好,但它都在那里并经过测试。
所以界面看起来有点像这样:
var data = GetData(); //Get the source data
var sa = new StreamAdaptor(); //This is what wraps the write-only utility source
sa.UpstreamSource((ps) => //ps is the dummy stream which does most of the magic
{
//This anon. function is run on a separate thread and can therefore be blocked
var sw = new StreamWriter(ps);
sw.AutoFlush = true;
var js = new Newtonsoft.Json.JsonSerializer();
js.Serialize(sw, data); //This is the main component of the implementation
sw.Flush();
});
var sa2 = new StreamAdaptor();
sa2.UpstreamSource((ps) =>
{
using (var gz = new System.IO.Compression.GZipStream(ps, System.IO.Compression.CompressionMode.Compress, true))
sa.CopyTo(gz);
});
通过自然支持读取管道,反向过程更容易
System.IO.Compression.GZipStream sw = new System.IO.Compression.GZipStream(sa2, System.IO.Compression.CompressionMode.Decompress);
var jsonTextReader = new JsonTextReader(new StreamReader(sw));
return TestA.Deserialize(jsonTextReader);
我还演示了IEnumerable&lt;&gt;的解决方法。反序列化问题。它需要您利用JsonTextReader创建自己的反序列化器,但它运行良好。
序列化程序本身支持IEnumerable。上面的GetData函数使用IEnumerable函数(以及其他内容)设置序列化程序的数据源:
public static IEnumerable<TestB> GetTestBs()
{
for (int i = 0; i < 2; i++)
{
var b = new TestB();
b.A = "A";
b.B = "B";
b.C = TestB.GetCs();
yield return b;
}
}
它的反序列化需要一种解决方法。请记住,IEnumerable&lt;&gt;属性需要全部列在JSON流/对象的末尾,因为枚举是延迟的,但JSON反序列化是线性的。
反序列化入口点:
public static TestA Deserialize(JsonTextReader reader)
{
TestA a = new TestA();
reader.Read();
reader.Read();
if (!reader.Value.Equals("TestBs"))
throw new Exception("Expected property 'TestBs' first");
reader.Read(); //Start array
a.TestBs = DeserializeTestBs(reader); //IEnumerable property last
return a;
}
IEnumerable反序列化函数之一:
static IEnumerable<TestB> DeserializeTestBs(JsonTextReader reader)
{
while (reader.Read())
{
if (reader.TokenType == JsonToken.EndArray)
break;
yield return TestB.Deserialize(reader);
}
reader.Read(); //End of object
}
这当然可以通过反复试验来实现,尽管JSON.NET中的内置支持是可取的。