multithreading

Aug 24, 2011 at 6:51 PM

Looking at the documentation for ZipFile it appears that the Save(), Read(), Add...(), and Extract() methods and their variations run asyncronosly to the calling thread. However that isn't explicitely mentioned one way or he other in the same documentation.

Do these block the calling thread until they complete or do they let the calling thread continue?

If they do block the calling thread then can they be called on a thread created for that purpose then will they raise events on the calling thread, on the thread that created the ZipFile, or on some other thread?

Jacob

Coordinator
Aug 24, 2011 at 7:38 PM

No, those methods are not asynchronous. I don't know why you would say that "it appears that they run asynchronously."  There's nothing in the documentation that suggests this, as far as I know. If I am wrong, please point out specifically where it says that they run asynchronously, and I will fix the documentation.

The ZipFile object should be used on a single thread only.  That ought to be clearly documented somewhere, too; not sure that it is.

 

Aug 24, 2011 at 7:56 PM

It doesn't explicitely say it, if it did I wouldn't have asked. What made me think that it might be is the presance of the ...Progress events.

Thanks for clarifying.

As to why you would want to do it, that I can answer. My app has a GUI and I will be storing the zip files at a remote location (over a "slow"/WAN connection). It could take 1-3 minutes for a save or extract operation to complete and in that time I don't want my GUI to stop responding.

That isn't a problem, I can easily wrap the entire ZipFile in a background thread. But, I needed to know if that was necissary.

Thank you for answering and thank you for this awesome tool.

Jacob

Coordinator
Aug 24, 2011 at 8:02 PM
Edited Aug 24, 2011 at 10:25 PM

The Progress events get fired from within the scope of Read(), Save() and Extract().

Think of it this way.  the ZipFile.Extract() method does a bunch of things.  The core of the method, though, is reading compressed data from the zip archive, uncompressing it, and writing that uncompressed data into a filesystem file.  It does this in chunks. Read a chunk of compressed stuff, decompress it, write the decompressed chunk.   If you have a 20mb file (uncompressed), it may compress to 8mb, and the read/write buffer is, let's say, 32k.  That means there will be about 256 iterations of the loop, reading and decompressing one chunk each time, just to decompress one complete file. This can take "a while".  During the course of this loop, the Extract() can make calls back into your code, via the ExtractProgress event, to inform you of its progress.  It's all synchronous.  During the event call itself, the call path goes from your code, into the DotNetLibrary, and then back into your code.  When your event handler is done, it returns, and control goes back into DotNetZip library code.

A similar thing happens in Read() and in Save().

You should save the zipfile in a bg thread.  You can use the SaveProgress events to update a progressbar, but the progress events will fire on the bg thread, so you will need to do the cross-thread invocation to make that happen.

you're welcome.

Nov 11, 2012 at 11:05 AM

I was wondering about the same thing, whether Save may return before completing, since I have the case where no exception is thrown and on a fast machine a (small) zip is created fine, but on a slower machine (not sure if that's the cause) the zip isn't saved

        if (dlg.ShowDialog() == true//TODO: find the parent window
          using (ZipFile zip = new ZipFile(Encoding.UTF8))
          {
            zip.Comment = "ClipFlair Options Archive";
             SaveOptions(zip); //saving to root folder
            zip.Save(dlg.OpenFile());
          }
I was wondering whether zip.Save(STREAM) may return before having saved to the STREAM and closed it (or do I need to close the output stream? note this is Silverlight code, where SaveFileDialog only gives me an output stream). If it is returning too soon, then the "using" clause disposes of the zip object
Unless it is that I need to close the stream myself and the different behaviour is cause the machines have other OS (eg it works on Windows Server 2008 R2 - maybe that closes the stream itself? - but fails on Windows 7)
Nov 12, 2012 at 1:06 AM
Edited Nov 12, 2012 at 1:09 AM

seems the issue in my case was I didn't make sure the output stream gets closed (it only worked on Windows Server). Change to the following:

        if (dlg.ShowDialog() == true//TODO: find the parent window
          using (Stream stream = dlg.OpenFile()) //will close the stream when done
            SaveOptions(stream);
also in SaveOptions, after zip.Save I also do a stream.Flush(); just in case to push any intermediate buffers to the output