2017-01-18 24 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脫身,解壓縮它並沒有緩衝區的字節任何地方,所以不存在時需要刷新任何緩衝區。