2017-01-18 16 views
0

Я хочу сжать объект ProtoBuffer для сериализации и декомпрессии при десериализации. К сожалению, C# stdlib предлагает только процедуры сжатия, которые работают на потоках, а не на байт [], что делает его немного более бессмысленным, чем вызов функции. Мой код до сих пор:Disposing 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 работает только случайно, и если я также должен использовать MemoryStreams.

Я знаю, что, возможно, я смогу решить эту проблему, просто используя библиотеку сжатия thrid party, но это, помимо того, что касается этого вопроса.

+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, чтобы он мог быть 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); 
     } 
    } 

Кроме того, хотя комментарий говорит «Call base.Close() для очистки асинхронной IO ресурсов» функции базовой Dispose из 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, при распаковке она не буфер байтов в любом месте, так что нет необходимо очистить любые буферы.