none
DeflateStream - MSDN Example is incorrect RRS feed

  • Question

  • Hello,

    I'm trying to use DeflateStream to decompress some data but all examples (including the MSDN) fail to give me any information at all.

    Below is the code I used to compress the data. (The data used was "ABCDEFGHIJKLMNOPQRSTUVWXYZ" which 'compressed' to 132 bytes.)
    static byte[] Compress(byte[] blob)
    		{
    			MemoryStream Source = new MemoryStream(blob);
    			MemoryStream Destination = new MemoryStream();
    
    			DeflateStream Zip = new DeflateStream(Destination, CompressionMode.Compress);
    
    
    
    			int bytesToRead = 0;
    			Source.Position = 0;
    			while (Source.Position < Source.Length)
    			{
    				if (Source.Length > int.MaxValue)
    					bytesToRead = int.MaxValue;
    				else
    					bytesToRead = (int)(Source.Length - Source.Position);
    
    				byte[] buf = new byte[bytesToRead];
    				Source.Read(buf, 0, bytesToRead);
    				Zip.Write(buf, 0, bytesToRead);
    			}
    
    
    			Zip.Flush();
    			Source.Close();
    
    			Console.WriteLine(blob.Length.ToString() + "b compressed to " + Destination.Length + "b");
    			return Destination.ToArray();
    		}
    This is the decompression code.

    static byte[] Decompress(byte[] blob)
    {
    	MemoryStream ms = new MemoryStream(blob);
    	DeflateStream unzip = new DeflateStream(ms, CompressionMode.Decompress);
    	MemoryStream OUTPUT = new MemoryStream();
    
    	ms.Position = 0;
    	StreamReader sr = new StreamReader(unzip);
    	string tmp = sr.ReadToEnd();
    //tmp remains zero length.
    
    	return OUTPUT.ToArray();
    }
    I've tried looping using ReadByte but this returns -1 on the first read. I've also tried reading the entire length of the stream but this also gives nothing (the buffer keeps default values and is not updated

    At this stage I'm beginning to wonder if the DeflateStream class is capable of decompressing at all or whether this is some bug.
    Monday, August 3, 2009 4:21 PM

Answers

  • Just to make that clear, the 132 bytes it returns is incomplete - if you use my version, it'll return 134 bytes. Now pass this to the Decompress and you'll see that Decompress works right. The reason you think Decompress does not work correctly is that you are passing it an incomplete byte array.
    http://blog.voidnish.com
    • Marked as answer by Luke_UK Wednesday, August 5, 2009 9:35 AM
    Tuesday, August 4, 2009 4:43 PM
    Moderator

All replies

  • You need to simply step through your code with the Debugger.
    You will see the problem.  Here's a hint...

    byte[] buf = new byte[bytesToRead];



    Mark the best replies as answers. "Fooling computers since 1971."
    Monday, August 3, 2009 5:15 PM
    Moderator
  • You are forgetting to close the Zip stream.  Change your code like this:

                //Zip.Flush();
                Zip.Close();
                byte[] retval = Destination.ToArray();
                Console.WriteLine(blob.Length.ToString() + "b compressed to " + retval.Length.ToString() + "b");
                return retval;


    Hans Passant.
    Monday, August 3, 2009 5:41 PM
    Moderator
  • Rudedog2 - That wasn't a very helpful post. The line you have highlighted is perfectly acceptable and I have, of course, stepped through the code using the debugger. If you have something more specific to add please do.

    nobugz - Thank you but your suggestion has no impact on the decompression method which is what the post was about.
    Tuesday, August 4, 2009 12:01 PM
  • Hmm, it will in fact work when you make the correction.  Your original code returns an empty array when you decompress.  If the issue is that the compressed data is larger than the input data, don't forget that there's header information added to the stream.  You won't get smaller output data until you add a realistic amount of input data.

    Hans Passant.
    Tuesday, August 4, 2009 12:56 PM
    Moderator
  • nobugz, the compression code is working perfectly. The problem is that the following line returns an empty string:

    string tmp = sr.ReadToEnd();

    It does this despite using the compressed data as the source.
    Tuesday, August 4, 2009 2:32 PM
  • I can't bring Mohammed to the mountain.  Your compression code is not okay, it forgets to close the stream.  The result is that decompressing it returns an empty string.

    Hans Passant.
    Tuesday, August 4, 2009 2:56 PM
    Moderator
  • Try this :

    static byte[] Compress(byte[] blob)
    {
      using (MemoryStream Source = new MemoryStream(blob))
      {
          using (MemoryStream Destination = new MemoryStream())
          {
              using (DeflateStream Zip = new DeflateStream(Destination, CompressionMode.Compress, true))
              {
                  int bytesToRead = 0;
                  Source.Position = 0;
                  while (Source.Position < Source.Length)
                  {
                      if (Source.Length > int.MaxValue)
                          bytesToRead = int.MaxValue;
                      else
                          bytesToRead = (int)(Source.Length - Source.Position);

                      byte[] buf = new byte[bytesToRead];
                      Source.Read(buf, 0, bytesToRead);
                      Zip.Write(buf, 0, bytesToRead);
                  }
                  Zip.Close();
                  Console.WriteLine(blob.Length.ToString() + "b compressed to " + Destination.Length + "b");
              }
              return Destination.ToArray();
          }
      }
    }


    http://blog.voidnish.com
    Tuesday, August 4, 2009 3:25 PM
    Moderator
  • You don't really need to call Close if you move the Console.WriteLine down (it's a superficial call anyway that's not relevant to your method) :

    static byte[] Compress(byte[] blob)
    {
      using (MemoryStream Source = new MemoryStream(blob))
      {
          using (MemoryStream Destination = new MemoryStream())
          {
              using (DeflateStream Zip = new DeflateStream(Destination, CompressionMode.Compress, true))
              {
                  int bytesToRead = 0;
                  Source.Position = 0;
                  while (Source.Position < Source.Length)
                  {
                      if (Source.Length > int.MaxValue)
                          bytesToRead = int.MaxValue;
                      else
                          bytesToRead = (int)(Source.Length - Source.Position);

                      byte[] buf = new byte[bytesToRead];
                      Source.Read(buf, 0, bytesToRead);
                      Zip.Write(buf, 0, bytesToRead);
                  }
              }
              Console.WriteLine(blob.Length.ToString() + "b compressed to " + Destination.Length + "b");
              return Destination.ToArray();
          }
      }
    }


    http://blog.voidnish.com
    Tuesday, August 4, 2009 3:27 PM
    Moderator
  • Just to be very clear about this:

    THE COMPRESS METHOD WORKS.

    DECOMPRESSING ONLY GIVES ME A BLANK STRING BACK AND THIS IS THE PROBLEM

    I'm very confused as to why you are all pointing to the Compress() method when the error is in Decompress() as I have stated. Would you prefer it if I started a new thread and only included the method with the error?

    I really do not understand what the problem is here or with the DECOMPRESS code. So if you would like to demonstrate your fantastic coding abilities please, by all means, do so and tell me what is wrong with the DECOMPRESS method.

    Thank you.

    Tuesday, August 4, 2009 4:38 PM
  • Just to be very clear about this:

    THE COMPRESS METHOD WORKS.

    DECOMPRESSING ONLY GIVES ME A BLANK STRING BACK AND THIS IS THE PROBLEM

    I'm very confused as to why you are all pointing to the Compress() method when the error is in Decompress() as I have stated. Would you prefer it if I started a new thread and only included the method with the error?

    I really do not understand what the problem is here or with the DECOMPRESS code. So if you would like to demonstrate your fantastic coding abilities please, by all means, do so and tell me what is wrong with the DECOMPRESS method.

    Thank you.


    Your Compress method is wrong. It seemingly works. Use my version and you'll get what everyone here is talking about.
    http://blog.voidnish.com
    Tuesday, August 4, 2009 4:42 PM
    Moderator
  • Just to make that clear, the 132 bytes it returns is incomplete - if you use my version, it'll return 134 bytes. Now pass this to the Decompress and you'll see that Decompress works right. The reason you think Decompress does not work correctly is that you are passing it an incomplete byte array.
    http://blog.voidnish.com
    • Marked as answer by Luke_UK Wednesday, August 5, 2009 9:35 AM
    Tuesday, August 4, 2009 4:43 PM
    Moderator
  • You can lead a horse to water... but some horses are idiots. And those should be capital Bs nish, just to be a nazi about it ;)
    Tuesday, August 4, 2009 4:54 PM
  • You can lead a horse to water... but some horses are idiots. And those should be capital Bs nish, just to be a nazi about it ;)

    Well my stubborn excuse is that I was copy/paste-ing his code :-)
    http://blog.voidnish.com
    Tuesday, August 4, 2009 5:04 PM
    Moderator
  • Touche, didn't notice that.
    Tuesday, August 4, 2009 5:46 PM
  • Nishant Sivakumar, thank you very much for taking the time to explain this (I have marked your response as the answer because of this). I was under the impression that Flush() would ensure that all of the data would have been written.

    If nobugz had simply said this to begin with then I would have understood and accepted the answer. Unfortunately it seemed, to me, that no one read my post so they were ignoring where the problem actually was.



    Thank you to everyone who responded but please include the reason for your answer in the future - it is much more helpful to explain why and show the correct way than it is to just give the answer and assume the OP will understand where they've gone wrong.
    Wednesday, August 5, 2009 9:42 AM
  • If nobugz had simply said this to begin with then I would have understood and accepted the answer. Unfortunately it seemed, to me, that no one read my post so they were ignoring where the problem actually was.
    Wow, make that a capital I.
    Hans Passant.
    Wednesday, August 5, 2009 11:37 AM
    Moderator