2017-01-18 23 views
0

我想在序列化时压缩ProtoBuffer对象,并在反序列化时解压缩。令人遗憾的是,C#stdlib只提供在流而不是byte []上工作的压缩例程,这使得它比函数调用更冗长。我的代码到目前为止:处置MemoryStreams和GZipStreams

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被完全管理的代码。我想知道如果反序列化只是偶然发生,以及我是否应该放弃MemoryStreams。

我知道我可以通过简单地使用第三方压缩库来解决这个问题,但这个问题除了这个问题之外还有点不同。

+0

如果我正确地记得'MemoryStream'是在它拥有对象的时候被抛弃的,在这种情况下''GZipStream'被处置。或者,这可能只是为'Image's ... – TheLethalCoder

+0

那么把它当作学习曲线,如果某件事实现了'IDisposable',它应该被丢弃,理想情况下使用'using'。编写正确使用和处理对象的代码,你首先不会看到这个问题。 – TheLethalCoder

+0

@TheLethalCoder [并不总是](https://blogs.msdn.microsoft.com/pfxteam/2012/03/25/do-i-need-to-dispose-of-tasks/),以“任务”为例,它是IDisposeable,但它的功能页面[你不需要这样做](https://msdn.microsoft.com/en-us/library/dd270681(v = vs.110).aspx#Anchor_2 )当面向.NET 4.5或更高版本时。 –

回答

0

GZipStream需要进行处理,以便将其缓冲区中的最终压缩块清除到其基础流,并且还会调用处理过的流,除非使用过载that takes in a bool and you pass in false

如果您在哪里使用未处置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); 
     } 
    } 

此外,虽然评论说:“呼叫base.Close()清理异步IO资源”基本处置功能从Stream类做什么都没有。

protected virtual void Dispose(bool disposing) 
    { 
     // Note: Never change this to call other virtual methods on Stream 
     // like Write, since the state on subclasses has already been 
     // torn down. This is the last code to run on cleanup for a stream. 
    } 

之所以这么说,解压缩GZipStream时,你可以有可能与未处置它出于同样的原因不处置将MemoryStream脱身,解压缩它并没有缓冲区的字节任何地方,所以不存在时需要刷新任何缓冲区。