2013-08-30 23 views
8

Ho il seguente pezzo di codice:DeflateStream non funziona su MemoryStream?

MemoryStream resultStream = new MemoryStream(); 
string users = ""//Really long string goes here 
BinaryFormatter bFormatter = new BinaryFormatter(); 
using (MemoryStream assignedUsersStream = new MemoryStream()) 
{ 
    bFormatter.Serialize(assignedUsersStream, users); 
    assignedUsersStream.Position = 0; 

    using (var compressionStream = 
     new DeflateStream(resultStream, CompressionLevel.Optimal)) 
    { 
     assignedUsersStream.CopyTo(compressionStream); 

     Console.WriteLine("Compressed from {0} to {1} bytes.", 
      assignedUsersStream.Length.ToString(), 
      resultStream.Length.ToString()); 
    } 
}    

la cosa è che resultStream è sempre vuoto!

Cosa sto facendo di sbagliato qui?

risposta

9

Metti la tua verifica WriteLine fuori dall'utilizzo. I buffer non sono ancora stati scaricati.

using (DeflateStream compressionStream = new DeflateStream(resultStream, CompressionLevel.Optimal)) 
{ 
    assignedUsersStream.CopyTo(compressionStream); 

    //Console.WriteLine("Compressed from {0} to {1} bytes.", 
    //  assignedUsersStream.Length.ToString(), resultStream.Length.ToString()); 
} 

Console.WriteLine("Compressed from {0} to {1} bytes.", 
    assignedUsersStream.Length, resultStream.ToArray().Length); 

E a parte, non hanno bisogno di tutti quei ToString() s in un WriteLine.

PS: Tutto ciò che fa un file Binary con una stringa è scrivere i byte con il prefisso lunghezza. Se non è necessario il prefisso (mia ipotesi), potrebbe diventare:

string users = "";//Really long string goes here 
byte[] result; 

using (MemoryStream resultStream = new MemoryStream()) 
{ 
    using (DeflateStream compressionStream = new DeflateStream(resultStream, 
      CompressionLevel.Optimal)) 
    { 
     byte[] inBuffer = Encoding.UTF8.GetBytes(users); 
     compressionStream.Write(inBuffer, 0, inBuffer.Length); 
    } 
    result = resultStream.ToArray(); 
} 

Il contrario è altrettanto facile, ma avrete bisogno di una stima della lunghezza massima di creare il buffer di leggere:

string users2 = null; 

using (MemoryStream resultStream = new MemoryStream(result)) 
{ 
    using (DeflateStream compressionStream = new DeflateStream(resultStream, 
      CompressionMode.Decompress)) 
    { 
     byte[] outBuffer = new byte[2048]; // need an estimate here 
     int length = compressionStream.Read(outBuffer, 0, outBuffer.Length); 
     users2 = Encoding.UTF8.GetString(outBuffer, 0, length);       
    }      
} 
+0

questo è tutto! molto! accetterò come risposta in un minuto – Leonardo

+0

Buono. Assicurati di leggere la risposta di Thomas sull'eliminazione di 1 MemoryStream e potresti anche sostituire il formattatore con 'Encoding.GetBytes()'. –

7

Questo perché lo DeflateStream non scarica i dati nel flusso sottostante finché non viene chiuso. Dopo la sua chiusura, resultStream conterrà i dati compressi. Notare che per impostazione predefinita, DeflateStream chiude il flusso sottostante quando è chiuso, ma non lo si desidera, quindi è necessario passare true per il parametro leaveOpen. Inoltre, non c'è bisogno di 2 flussi di memoria, si può solo serializzare direttamente al compressionStream:

string users = ""; //Really long string goes here 
    BinaryFormatter bFormatter = new BinaryFormatter(); 
    using (MemoryStream resultStream = new MemoryStream()) 
    { 
     using (DeflateStream compressionStream = new DeflateStream(resultStream, CompressionLevel.Optimal, true)) 
     { 
      bFormatter.Serialize(compressionStream, users); 
      Console.WriteLine(resultStream.Length); // 0 at this point 
     } 
     Console.WriteLine(resultStream.Length); // now contains the actual length 
    } 
+2

Lo streaming non deve rimanere aperto, ToArray() funzionerà correttamente su un MemoryStream chiuso. Ma ho concordato di serializzare direttamente. –

+0

@HenkHolterman, hai ragione; Stavo ricevendo un'eccezione durante l'accesso alla lunghezza del flusso, ma ToArray funziona correttamente. –

3

Dalla risposta originale (non ho abbastanza crediti di voto verso il basso)

Put il vostro WriteLine controllo al di fuori del usando

Questo è incompleta e fuorviante. DeflateStream chiude il risultato finale sottostante una volta DeflateStream esce dal campo di applicazione. Pertanto resultStream.Length getta

Unhandled Exception: System.ObjectDisposedException: Cannot access a closed Stream. 

Thomas Levesque è corretta => inoltre impostare leaveOpen su true.

Una domanda interessante con alcuni punti positivi sollevati da HH e TL.

+0

Non l'ho visto prima, ma accedere allo stream dopo averlo eliminato è abbastanza normale, __a tanto quanto è un MemoryStream__. Questo non era chiaro nel mio primo frammento, ma è nel secondo, più lungo e nella domanda. –

+0

Grazie per l'aggiornamento; notato :-) –