Using DeflateStream

Oct 31, 2009 at 1:14 AM
Edited Oct 31, 2009 at 6:09 AM

Hi guys!

I have a problem while trying to use DeflateStream. If I do it in the way suggested in one of your examples it works fine.  Though if I change file stream to memory stream creating a DeflateStream object I get some problems. Code below is just slightly modified sample from DeflateStream.cs

 

    string fileToCompress = @"d:\d1.doc";
    using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress))
    {
         using (var raw = System.IO.File.Create(fileToCompress + ".zip"))
         {
/*             using (DeflaterOutputStream deflaterStream = new DeflaterOutputStream(raw))
             {
                 MiscUtil.CopyStream(input, deflaterStream);
                 deflaterStream.Finish();
             }*/
             // Stream compressor = new DeflateStream(raw, CompressionMode.Compress);
             MemoryStream ms = new MemoryStream();
             
             using (Stream compressor = new DeflateStream(ms, CompressionMode.Compress))
             {
                 byte[] buffer = new byte[4096];
                 int n;
                 while ((n = input.Read(buffer, 0, buffer.Length)) != 0)
                 {
                     compressor.Write(buffer, 0, n);
                 }
                 MiscUtil.CopyStream(ms, raw);
             }
             /*     MemoryStream ms = new MemoryStream();
             ZipUtil.Deflate(input, ms);
             MiscUtil.CopyStream(ms, raw);*/
         }
     }

 

    string fileToCompress = @"d:\d1.doc";

    using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress))

    {

         using (var raw = System.IO.File.Create(fileToCompress + ".zip"))

         {

             MemoryStream ms = new MemoryStream();

             using (Stream compressor = new DeflateStream(ms, CompressionMode.Compress))

             {

                 byte[] buffer = new byte[4096];

                 int n;

                 while ((n = input.Read(buffer, 0, buffer.Length)) != 0)

                 {

                     compressor.Write(buffer, 0, n);

                 }

                 MiscUtil.CopyStream(ms, raw);  // this is just a stream to stream copy utility function

             }

         }

     }

I set a break on MiscUtil.CopyStream(ms, raw) and found that ms.Length = ms.Position = 0. Could you please comment if this is the real issue or I just do something wrong?
Thanks in advance,
Alex

 

 

Coordinator
Oct 31, 2009 at 6:32 AM

I don't know what the specific problem might be but I have some comments.

  1. If I thought my code had written to a stream, and yet the Position and Length on the stream were both 0, I would first verify that the stream write actually occurred.
  2. I don't know what CopyStream does, but if you do a ms.Read() in there, you will want to call ms.Seek(0, SeekOrigin.Begin) before doing so. 
  3. Why do you write to a MemoryStream when you really want to put it into the filesystem file?  Why not write directly to the filestream?   what are you trying to accomplish?
  4. The file you are creating, with the .zip extension, is not a zip file.  Anything that comes out of DeflateStream is not a .zip file.  You are inviting confusion by naming it that way.  

Good luck!

Oct 31, 2009 at 9:16 AM

Thank you for quick reply.

1. Before going to debug the dotnetzip code I wanted to check if it's not a feature of the library.

2. I am not sure that it is really necessary in this case but ok, i will try. Though in all other code this function works fine so I am pretty sure that it is a root cause of the problem.

3. It's just for testing purposes. In fact I need to deflate a memory stream and continue to work with it.

4. Yeah, I know it. Again it was just for testing purposes so I named the file with the first name I had in my head. I am agree it could be confusing.

By the way, I am not really good in C# but do I understand rightly, that even if I solve the issue and find the way to write a deflated stream into a memory stream I will have to copy its contant, as far as the stream will be closed then DeflateStream is disposed?

Coordinator
Oct 31, 2009 at 9:58 AM

> Though in all other code this function works fine so I am pretty sure that it is a root cause of the problem.

No, you are not understanding.  If a stream is of length 100, and the Position on the stream is 100, then calling Read() on the stream will not return any data.  In the MemoryStream, after having written it, the Position is at the end of whatever data you've written.  This isn't the problem you're having, if Length and Position are both zero, but it will be a problem, if you fix the first one.

> I will have to copy its contant, as far as the stream will be closed then DeflateStream is disposed?

There's a constructor on the DeflateStream class that lets you specify whether you want the internal stream to remain open, or not, after closing the DeflateStream.

http://cheeso.members.winisp.net/DotNetZipHelp/html/c19f2a7a-1c21-a979-3cf1-40f87a008c88.htm 

 

Oct 31, 2009 at 12:15 PM

Ah, I got it. Yes, the  position is set to 0 before starting the copy process.

Thanks for hint with a constractor, it is useful. I missed it by carelessness.

Nov 1, 2009 at 12:41 AM

Hello again!

I didn't investigate the code much but it looks like some buffers are written to the stream in the ZLibStream.finish() method. That's why using IO stream led to correct behavior and using memory stream failed - in case of memory stream finish() wasn't called. After making finish() method public and changing a part of code like this:

           using (DeflateStream compressor = new DeflateStream(ms, CompressionMode.Compress))

             {

                 byte[] buffer = new byte[4096];

                 int n;

                 while ((n = input.Read(buffer, 0, buffer.Length)) != 0)

                 {

                     compressor.Write(buffer, 0, n);

                 }

                 compressor.Finish()

                 MiscUtil.CopyStream(ms, raw);  // this is just a stream to stream copy utility function

        }

i was able to deflate a file to memory stream and then inflate it back. For me it looks like an issue but again, probably I misused your code. Could you please comment?

 

Best regards,

Alex

Coordinator
Nov 1, 2009 at 12:57 AM

Ah, yes, I should have caught that.   You don't need finish() to be public.

You only need to call Close() on the DeflateStream, before reading the MemoryStream.  Reading the MemoryStream after the exit of the using() clause is sufficient.  Like so:

var ms = new MemoryStream();
using (DeflateStream compressor = new DeflateStream(ms, CompressionMode.Compress))
{
     byte[] buffer = new byte[4096];
     int n;
     while ((n = input.Read(buffer, 0, buffer.Length)) != 0)
     {
         compressor.Write(buffer, 0, n);
     }
}  // the finish() method is called here, implicitly
MiscUtil.CopyStream(ms, raw);

Nov 3, 2009 at 1:41 AM

Thanks a lot!

It's nice to deal with you.

Nov 10, 2009 at 4:07 AM

Hello again!

One more time the help is needed. Here is a unit test:

 

        [Test]
        public void UnifiedTestTextboxWithImage()
        {
            string fileToCompress = @"d:\inflated1";
            using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress))
            {
                using (Stream raw = System.IO.File.Create(@"d:\deflated_"))
                {
                    MemoryStream ms = new MemoryStream();
                    using (Stream compressor = new DeflateStream(ms, CompressionMode.Compress, true))
                    {
                        byte[] buffer = new byte[4096];
                        int n;
                        while ((n = input.Read(buffer, 0, buffer.Length)) != 0)
                        {
                            compressor.Write(buffer, 0, n);
                        }
                    }
                    ms.Position = 0;
                    MiscUtil.CopyStream(ms, raw);
                }
            }
            using (System.IO.Stream srcStream = System.IO.File.OpenRead(@"d:\deflated_"))
            {
                using (Stream raw = System.IO.File.Create(@"d:\inflated_"))
                {
                    Stream inflaterStream = new DeflateStream(srcStream, CompressionMode.Decompress);
                    MemoryStream dstStream = new MemoryStream();
                    using (inflaterStream)
                    {
                        // MiscUtil.CopyStream(inflaterStream, dstStream);
                        int nByte;
                        byte[] buffer = new byte[519];
                        while ((nByte = inflaterStream.Read(buffer, 0, buffer.Length)) != 0)
                        {
                            dstStream.Write(buffer, 0, nByte);
                        }
                    }
                    dstStream.Position = 0;
                    MiscUtil.CopyStream(dstStream, raw);
                }
            }
            //    TestShapeTextboxes.UnifiedTestTextboxWithImage(MyLoadFormat, MySaveFormat);
        }

 

        [Test]

        public void DeflateTest()

        {

            using (System.IO.Stream input = System.IO.File.OpenRead(@"d:\inflated1"))

            {

                using (Stream raw = System.IO.File.Create(@"d:\deflated_"))

                {

                    using (Stream compressor = new DeflateStream(raw, CompressionMode.Compress, true))

                    {

                        byte[] buffer = new byte[4096];

                        int n;

                        while ((n = input.Read(buffer, 0, buffer.Length)) != 0)

                            compressor.Write(buffer, 0, n);

                    }

                }

            }

            using (System.IO.Stream srcStream = System.IO.File.OpenRead(@"d:\deflated_"))

            {

                using (Stream raw = System.IO.File.Create(@"d:\inflated_"))

                {

                    Stream inflaterStream = new DeflateStream(srcStream, CompressionMode.Decompress);

                    using (inflaterStream)

                    {

                        int nByte;

                        byte[] buffer = new byte[519];

                        while ((nByte = inflaterStream.Read(buffer, 0, buffer.Length)) != 0)

                            raw.Write(buffer, 0, nByte);

                    }

                }

            }

        }

The size of inflated1 is 518 bytes. If the size of inflate buffer is <=518 then test passes and output file is identical to source file. If the buffer size is > 518 (519 in this case) inflaterStream.Read returnes 0, though the buffer  is re-written with correctly inflated data. 
from what i can see in debugger in ZlibStream.Read in do-while loop in the second pass _z.Inflate(_flushMode) returnes ZlibConstants.Z_BUF_ERROR in
                    rc = (_wantCompress)
                        ? _z.Deflate(_flushMode)
                        : _z.Inflate(_flushMode);
Thanks in advance,
Alex

 

 

Coordinator
Nov 10, 2009 at 5:03 AM

Alex, I don't understand the problem.  I understand everything you wrote, up to this point;

The size of inflated1 is 518 bytes. If the size of inflate buffer is <=518 then test passes and output file is identical to source file.

I don't know what problem you are seeing.  I don't know what you're trying to describe.  IS there an exception? IS the file being inflated incorrectly?  What problem are you seeing?

Nov 10, 2009 at 5:29 AM

Sorry for misleading.

Ok, here is the scenario. I have a file named inflated1. I deflate it and save in a file named deflated_. Up to here everything works fine. 

Next I read the file deflated_  and try to inflate it and save into a file inflated_ to be able co compare with initial file.

I use the code a posted above to do both this operation in a test. The size of original file is 518 byte.

If i set the size of a  buffer i use to inflate the data to equal o less then 518 bytes then the code works fine and file is inflated correctly.

If I make a buffer of size greater then 518 (in this example it is 519)

                     byte[] buffer = new byte[519];

then the error occures. There is no exeption thrown but here

nByte = inflaterStream.Read(buffer, 0, buffer.Length)

nBytes = 0 though in debugger i can see that the buffer is changed. Moreover, if on this step i change nByte and set it nByte=518 in the debugger test passes, that is the data wrote to the buffer are correctly inflated.

 

 

Coordinator
Nov 10, 2009 at 7:55 AM

ok, Thanks for the additional explanation. It's very clear now.

I just tried your code and I could not reproduce what you saw.  I tried a file of length 518 and buffers of length 517, 518, and 519.  I always got the same results, correct results. I also tried files of longer and shorter length, with the same range of buffer size.  I tried DotNetZip v1.8.4.24 and v1.9.0.29. 

It could be the error is related to the actual data in the buffer you compress.  Can you make that file available?

 

Nov 10, 2009 at 8:26 AM

Sure.

Could you please email me at anovickov (at) mail (dot) ru and I reply to you with a test file.

Coordinator
Nov 10, 2009 at 8:57 AM

ok, I did that. Awaiting your reply.

Nov 18, 2009 at 7:38 AM

Hi Cheeso,

Did you receive a test file from me?

Could you confirm or decline the issue?

Regards,

Alex

Coordinator
Nov 18, 2009 at 9:25 AM

No, I did not receive an email.  I sent one to you, on the 10th of November, but I did not see a reply.

Nov 18, 2009 at 10:57 AM

It's strange, casue i have sent you three emails on 10, 11 and 17. Could it be that my mails felt in spam box?

Resent again from mail.ru and gmail.com

Nov 19, 2009 at 9:50 AM

Hi Cheeso, did you receive it this tiem?

Alex

Coordinator
Nov 19, 2009 at 12:11 PM

Yes I did. I just receievd your email.  Only the one from gmail.com . 

I'll let you know what I find.

Nov 27, 2009 at 11:57 AM

Bongiorno Dino,

Any findings?

 

 

Coordinator
Dec 2, 2009 at 6:01 AM

nothing yet. . .

Dec 2, 2009 at 6:05 AM

But do you at least confirm that the problem exists?