2017-01-18 5 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が完全に管理されたコードになると思うのだろうかと思います。 Deserializeがうまく動作しない場合や、MemoryStreamを処分する必要があるかどうかは不思議です。

私はおそらく、単にこのパーティーの圧縮ライブラリを使用してこの問題を解決することができますが、それはこの質問のポイントの外にある程度です。

+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/)、たとえば「タスク」を取るそれはIDisposableですが、関数のページには[あなたはそれをする必要はありません]と書かれています(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を使用しない限り、渡したストリームでdisposeを呼び出します。

MemoryStreamを処分しなかった過負荷を使用している場合は、内部バッファをどこにでも書き込んでいないため、MemoryStreamを処分するほど重要ではありません。それが行う唯一の事柄はいくつかのフラグを設定し、Taskオブジェクトをヌルに設定するので、ストリームの有効期間がディスポジションポイントよりも長い場合は、GCedをすぐに行うことができます。コメントは言うものの、また

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); 
     } 
    } 

、全く何もしない Streamクラスからベースにdispose機能「IOリソース非同期(async)クリーンアップに()を呼び出しbase.Close」。

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をを配置していないのと同じ理由のためにそれを配置しないで逃げることができ、言われていますバッファをフラッシュする必要があります。

関連する問題