流适配器为写出实用程序提供写入接口,还提供读出接口

时间:2014-04-28 05:05:57

标签: c# stream json.net gzipstream

我不喜欢在流接口之间使用MemoryStream对象。它们很笨拙,要求您重新开始寻找,并且在苛刻的情况下也会使内存使用达到峰值。

有时,实用程序只能以某种方式工作。也许它会输出byte [],或写入流,或者是您读取的管道中的流,从中拉出数据。

这个Newtonsoft JSON序列化程序是一个只能写入流的实用程序。

var js = new Newtonsoft.Json.JsonSerializer();
var sw = new StreamWriter(ps);
js.Serialize(sw, o);

这对我来说是一个问题,因为我想链接:

  • 的IEnumerable
  • JSON序列化
  • GZIP压缩
  • HTTP到客户端
  • (网络)
  • 来自服务器的HTTP
  • GZIP减压
  • JSON反序列化
  • 的IEnumerable

除了让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)需要一个解决方案。

  1. 是否有任何解决方案可以让人们更有效地加入这些公用事业?
  2. 是否有一个包含适用于此类情况的适配器的库?
  3. 我正在研究这样一个图书馆,不要指望有这样的图书馆。

1 个答案:

答案 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中的内置支持是可取的。