tags:

views:

102

answers:

4

Hi all, I have the following method and for some reason the first call to Copy to seems to do nothing? Anyone know why? In input to the method is compressed and base64 can supply that method to if need.

private byte[] GetFileChunk(string base64)
    {
        using (
            MemoryStream compressedData = new MemoryStream(Convert.FromBase64String(base64), false),
            uncompressedData = new MemoryStream())
        {

            using (GZipStream compressionStream = new GZipStream(compressedData, CompressionMode.Decompress))
            {
                // first copy does nothing ?? second works
                compressionStream.CopyTo(uncompressedData);
                compressionStream.CopyTo(uncompressedData);
            }

            return uncompressedData.ToArray();
        }
    }
+1  A: 

Just a guess, but is it because the new GZipStream constructor leaves the index at the end of the array, and the first CopyTo resets it to the start, so that when you call the second CopyTo its now at the start and copies the data properly?

w69rdy
+1  A: 

How sure are you that first copy does nothing and the second works , that would be a bug in the GZipStream class. Your code should work fine without calling CopyTo twice.

Ben Robinson
The first copy does not populate the stream; get same behaviour with the read method. The GZipStream is a Microsoft class surly there is not an error in there class?
Dan H
Hmm are you 100% sure. Read is a different matter entirely the contract on the read method says it is not guaranteed to return the amount of bytes requested but the CopyTo documentation does not make the same claim, but perhaps it uses the Read method internally. Have you tried using it in a loop ex per the example on the Stream.Read MSDN page http://msdn.microsoft.com/en-us/library/system.io.stream.read.aspx
Ben Robinson
Ya started with a loop, the first call to read returns 0, subsequent calls to read return bytes until the end.
Dan H
AS i said this is nexpected behaviour with Read and it is documented in the linked MSDN article, however the CopyTo should not behave like this, or at least there is nothing in the documentation that says that it should.
Ben Robinson
+2  A: 

If the first call to Read() returns 0 then Stream.CopyTo() isn't going to work either. While this points to a problem with GZipStream, it is very unlikely that it has a bug like this. Far more likely is that something went wrong when you created the compressed data. Like compressing 0 bytes first, followed by compressing the real data.

Hans Passant
A: 

Hi thank you for everybody’s input. It turns out the error was caused by a mistake in encoding method. The method was

  /// <summary>
    /// Compress file data and then base64s the compressed data for safe transportation in XML.
    /// </summary>
    /// <returns>Base64 string of file chunk</returns>
    private string GetFileChunk()
    {
        // MemoryStream for compression  output
        using (MemoryStream compressed = new MemoryStream())
        {
            using (GZipStream zip = new GZipStream(compressed, CompressionMode.Compress))
            {

                // read chunk from file
                byte[] plaintext = new byte[this.readSize];
                int read = this.file.Read(plaintext, 0, plaintext.Length);

                // write chunk to compreesion
                zip.Write(plaintext, 0, read);
                plaintext = null;

                // Base64 compressed data
                return Convert.ToBase64String(compressed.ToArray());
            }
        }
    }

The return line should be below the using allowing the compression stream to close and flush, this caused the inconsistent behaviour when decompressing the stream.

        /// <summary>
    /// Compress file data and then base64s the compressed data for safe transportation in XML.
    /// </summary>
    /// <returns>Base64 string of file chunk</returns>
    private string GetFileChunk()
    {
        // MemoryStream for compression  output
        using (MemoryStream compressed = new MemoryStream())
        {
            using (GZipStream zip = new GZipStream(compressed, CompressionMode.Compress))
            {

                // read chunk from file
                byte[] plaintext = new byte[this.readSize];
                int read = this.file.Read(plaintext, 0, plaintext.Length);

                // write chunk to compreesion
                zip.Write(plaintext, 0, read);
                plaintext = null;
            }

            // Base64 compressed data
            return Convert.ToBase64String(compressed.ToArray());
        }
    }

Thank you for everybody's help.

Dan H