GZipStream weird behavior.

R

Rene

The snipped of code below will not work unless I un-rem the
"compressZip.Close()" instruction.

Question: Why do I need to close the GZipStream object used for compression
in order to successfully use a GZipStream to decompress??? To me they should
be totally independent form one another. What am I missing?

Thanks.

---------------------------------------------------

// Info to compress.
byte[] compressThis = new byte[] { 1, 2, 3 };

// Compress.
MemoryStream compressStream = new MemoryStream();
GZipStream compressZip = new GZipStream(compressStream,
CompressionMode.Compress, true);
compressZip.Write(compressThis, 0, compressThis.Length);
//compressZip.Close(); // Unrem this to make things work.

// Decompress and display.
MemoryStream decompressStream = new MemoryStream(compressStream.ToArray());
GZipStream decompressZip = new GZipStream(decompressStream,
CompressionMode.Decompress);
byte[] result = new byte[3];
decompressZip.Read(result, 0, result.Length);
Console.WriteLine("{0} {1} {2}", result[0], result[1], result[2]);
Console.Read();
 
N

Nicholas Paldino [.NET/C# MVP]

Rene,

Well, according to the documentation, calling the Close method will
cause the encoder to flush the remaining contents to the stream.
Additionally, it states in the documentation for Close:

A call to Close is required for proper operation of a stream

You should be using a using statement for your streams. Also, you don't
have to create a new memory stream, rather, you can just set the pointer of
the stream to the beginning, and use that.

Your code should look like this:

// Info to compress.
byte[] compressThis = new byte[] { 1, 2, 3 };

// Compress.
// using statement not needed, but it is good practice, since it implements
IDisposable.
using (MemoryStream compressStream = new MemoryStream())
{
// Using SHOULD be used here.
using (GZipStream compressZip = new GZipStream(compressStream,
CompressionMode.Compress, true))
{
// Write to the stream.
compressZip.Write(compressThis, 0, compressThis.Length);

// Stream gets closed here.
}

// Reset stream to beginning.
compressStream.Position = 0;

// Decompress.
using (GZipStream decompressZip = new GZipStream(decompressStream,
CompressionMode.Decompress))
{
// Get the results.
byte[] result = new byte[3];

// It should be noted that this is not an accurate way to read from
a stream, it's not always
// guaranteed that Read will return the number of bytes requested.
The implementation of the
// Stream abstract class (MemoryStream) probably guarantees this,
but the contract (the abstract
// Stream class) does not.
decompressZip.Read(result, 0, result.Length);

// Write the results.
Console.WriteLine("{0} {1} {2}", result[0], result[1], result[2]);
}
}

// Wait for input.
Console.Read();


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Rene said:
The snipped of code below will not work unless I un-rem the
"compressZip.Close()" instruction.

Question: Why do I need to close the GZipStream object used for
compression in order to successfully use a GZipStream to decompress??? To
me they should be totally independent form one another. What am I missing?

Thanks.

---------------------------------------------------

// Info to compress.
byte[] compressThis = new byte[] { 1, 2, 3 };

// Compress.
MemoryStream compressStream = new MemoryStream();
GZipStream compressZip = new GZipStream(compressStream,
CompressionMode.Compress, true);
compressZip.Write(compressThis, 0, compressThis.Length);
//compressZip.Close(); // Unrem this to make things work.

// Decompress and display.
MemoryStream decompressStream = new
MemoryStream(compressStream.ToArray());
GZipStream decompressZip = new GZipStream(decompressStream,
CompressionMode.Decompress);
byte[] result = new byte[3];
decompressZip.Read(result, 0, result.Length);
Console.WriteLine("{0} {1} {2}", result[0], result[1], result[2]);
Console.Read();
 
R

Rene

Thanks Nicholas

I should have pointed out that the snippet of code was formatted in such a
way so that it was easy to follow and understand. I purposely avoid adding
the "using" statement on an effort to eliminate clutter. The snippet does
not represent "real code" is just there to illustrate the problem.

I also should have pointed out that I purposely avoid reusing the same
memory stream. I purposely used the "new
MemoryStream(compressStream.ToArray())" to make it clear that the memory
stream associated with the GZipStream object used for *decompression* had
nothing to do with the memory stream associated with the GZipStream used for
*compression*. This is because as far as I know, the "ToArray()" method will
create a brand new byte array that is completely unassociated with the old
memory stream.

Having said that, I still don't understand why I need to close the
GZipStream used for compressing in order for me to be able to decompress. As
you can see from my sample code, the GZipStream used to decompress is a
*completely different* object using a *completely different* memory stream
one should have nothing to do with the other.

What am I not getting here?
 
N

Nicholas Paldino [.NET/C# MVP]

Rene,

You are using a stream that creates a transformation which is dependent
on the state of other parts of the transformed stream. Because of this,
there is usually state that is reserved to be written at the end of the
operation (CryptoStream does this as well). GZipStream performs such an
operation, so you need to finalize it just the same.
 
R

Rene

Ok, now I get it, for a second I thought it had something to do with me not
having called Flush() on the GZipStream object or something like that.

The real question here is how the heck you know so much?? What do you eat??
I mean, I spend countless hours a day reading for yeas now and I am still as
much as a dumb @ss as when I started.

For example, how the heck did you find out about the GZipStream writing
extra bytes of information when it's closed?

Thanks a million!



Nicholas Paldino said:
Rene,

You are using a stream that creates a transformation which is dependent
on the state of other parts of the transformed stream. Because of this,
there is usually state that is reserved to be written at the end of the
operation (CryptoStream does this as well). GZipStream performs such an
operation, so you need to finalize it just the same.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Rene said:
Thanks Nicholas

I should have pointed out that the snippet of code was formatted in such
a way so that it was easy to follow and understand. I purposely avoid
adding the "using" statement on an effort to eliminate clutter. The
snippet does not represent "real code" is just there to illustrate the
problem.

I also should have pointed out that I purposely avoid reusing the same
memory stream. I purposely used the "new
MemoryStream(compressStream.ToArray())" to make it clear that the memory
stream associated with the GZipStream object used for *decompression* had
nothing to do with the memory stream associated with the GZipStream used
for *compression*. This is because as far as I know, the "ToArray()"
method will create a brand new byte array that is completely unassociated
with the old memory stream.

Having said that, I still don't understand why I need to close the
GZipStream used for compressing in order for me to be able to decompress.
As you can see from my sample code, the GZipStream used to decompress is
a *completely different* object using a *completely different* memory
stream one should have nothing to do with the other.

What am I not getting here?
 
N

Nicholas Paldino [.NET/C# MVP]

Rene,

I don't know that I know so much? I just do? I mean, I spend a good
amount of time answering questions here, which causes me to have to look in
the documentation a great deal.

As for what I eat, it depends on the day. Last night, sushi. Tonight,
bacon ice cream. Lunch is a salad. Lots of fruit. While I don't
specifically avoid fatty foods, I do try to stay away from the unnatural
stuff (I would take fried chicken that I make over a twinkee anyday).

As for writing extra bytes of information when it is closed, I do
remember reading the zip specification once, and remembering that the
algorithm keeps tables of compressed information (IIRC) meaning that it is
an iterative transformation.

I just took it from there.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)


Rene said:
Ok, now I get it, for a second I thought it had something to do with me
not having called Flush() on the GZipStream object or something like that.

The real question here is how the heck you know so much?? What do you
eat?? I mean, I spend countless hours a day reading for yeas now and I am
still as much as a dumb @ss as when I started.

For example, how the heck did you find out about the GZipStream writing
extra bytes of information when it's closed?

Thanks a million!



Nicholas Paldino said:
Rene,

You are using a stream that creates a transformation which is
dependent on the state of other parts of the transformed stream. Because
of this, there is usually state that is reserved to be written at the end
of the operation (CryptoStream does this as well). GZipStream performs
such an operation, so you need to finalize it just the same.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Rene said:
Thanks Nicholas

I should have pointed out that the snippet of code was formatted in such
a way so that it was easy to follow and understand. I purposely avoid
adding the "using" statement on an effort to eliminate clutter. The
snippet does not represent "real code" is just there to illustrate the
problem.

I also should have pointed out that I purposely avoid reusing the same
memory stream. I purposely used the "new
MemoryStream(compressStream.ToArray())" to make it clear that the memory
stream associated with the GZipStream object used for *decompression*
had nothing to do with the memory stream associated with the GZipStream
used for *compression*. This is because as far as I know, the
"ToArray()" method will create a brand new byte array that is completely
unassociated with the old memory stream.

Having said that, I still don't understand why I need to close the
GZipStream used for compressing in order for me to be able to
decompress. As you can see from my sample code, the GZipStream used to
decompress is a *completely different* object using a *completely
different* memory stream one should have nothing to do with the other.

What am I not getting here?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top