DeflateStream doesnt work on MemoryStream?

Leonardo picture Leonardo · Aug 30, 2013 · Viewed 12k times · Source

I have the following piece of code:

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

the thing is that resultStream is always empty!

What am I doing wrong here?

Answer

Henk Holterman picture Henk Holterman · Aug 30, 2013

Put your verification WriteLine outside of the using. The buffers haven't been flushed yet.

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

And aside, you don't need all those ToString()s in a writeline.

PS: All a BinaryFormatter does with a string is write the bytes with length prefix. If you don't need the prefix (my guess), it could become:

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

The reverse is just as easy but you'll need an estimate of the maximum length to create the read-buffer:

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