我想在序列化时压缩ProtoBuffer对象并在反序列化时解压缩。不幸的是,C#stdlib只提供了对流而不是byte []的压缩例程,这使得它比函数调用更加冗长。我的代码到目前为止:
class MyObject{
public string P1 {get; set;}
public string P2 {get; set;}
// ...
public byte[] Serialize(){
var builder = new BinaryFormat.MyObject.Builder();
builder.SetP1(P1);
builder.SetP2(P2);
// ...
// object is now build, let's compress it.
var ms = new MemoryStream();
// Without this using, the serialisatoin/deserialisation Tests fail
using (var gz = new GZipStream(ms, CompressionMode.Compress))
{
builder.Build().WriteTo(gz);
}
return ms.ToArray();
}
public void Deserialize(byte[] data)
{
var ms = new MemoryStream();
// Here, Tests work, even when the "using" is left out, like this:
(new GZipStream(new MemoryStream(data), CompressionMode.Decompress)).CopyTo(ms);
var msg = BinaryFormat.MachineInfo.ParseFrom(ms.ToArray());
P1 = msg.P1;
P2 = msg.P2;
// ...
}
}
处理流时,似乎必须手动处理对象。我想知道为什么会这样,我希望GZipStream是完全托管的代码。我想知道如果Deserialize只是偶然起作用,我是否应该处理MemoryStreams。
我知道我可以通过简单地使用第三方压缩库来解决这个问题,但除了这个问题之外,这还有点。
答案 0 :(得分:1)
GZipStream
,因此它将其缓冲区的最终压缩块从其缓冲区刷新到其底层流,它还会在传入的流上调用dispose,除非您使用了重载{{ 3}}
如果您使用未处理MemoryStream
的重载,那么放置MemoryStream
并不重要,因为它没有在任何地方写入其内部缓冲区。它唯一能做的就是设置一些标志并将Task
对象设置为null,这样如果流的生命周期长于处置点,它就可以更快地进行GC。
protected override void Dispose(bool disposing)
{
try {
if (disposing) {
_isOpen = false;
_writable = false;
_expandable = false;
// Don't set buffer to null - allow TryGetBuffer, GetBuffer & ToArray to work.
#if FEATURE_ASYNC_IO
_lastReadTask = null;
#endif
}
}
finally {
// Call base.Close() to cleanup async IO resources
base.Dispose(disposing);
}
}
此外,虽然评论说&#34;调用base.Close()来清理异步IO资源&#34; <{1}}类的base dispose函数什么都不做。
Stream
所有这一切,在解压缩GZipStream时,你可能会因为没有处理MemoryStream而放弃它,因为解压缩它不会在任何地方缓冲字节,所以不需要刷新任何缓冲区。 / p>