Best Way to "Cancel" ZipFile.Save?

Apr 15, 2011 at 8:17 PM

I have a  ... (using ZipFile blah = new ZipFile()) { ... } within a backgroundWorkerThread. I tried throwing in some if (cancellation) statements within my file/dir recursions like:


 foreach (string dir in classy.dirs)
                        string DirToPutIn;
                        string[] fpath = dir.Split('\\');
                        DirToPutIn = fpath[fpath.Length - 1];
                        zippy.AddDirectory(dir, DirToPutIn);

                        //check if the user has tried to cancel the thread
                        if (worker.CancellationPending)
                            e.Cancel = true;

Is this the "wrong" way to abort the ZipFile.Save process? Is there a "right" way?

Apr 15, 2011 at 8:51 PM

Put the cancellation code (CancellationPending, e.Cancel = True) in the progress indicators, so that the process can be cancelled before it has finished. There is some example code on how to get the indicators set up on the examples page.

Apr 15, 2011 at 10:09 PM

Sorry for my ignorance. I have a SaveProgress event handler setup already to update some UI stuff like

 public void SaveProgress(object sender, SaveProgressEventArgs e)

            if (e.EventType == ZipProgressEventType.Saving_Started)
                this.UIThread(() => this.Text =  "Saving: " + e.ArchiveName);
                this.UIThread(() => this.label2.Text = "to " + e.ArchiveName);
            else if (e.EventType == ZipProgressEventType.Saving_BeforeWriteEntry)
                this.UIThread(() => label1.Text = "Writing: " + e.CurrentEntry.FileName + 
                    " (" + (e.EntriesSaved + 1) + "/" + e.EntriesTotal + ")"

                this.UIThread(() => progressBar2.Maximum = e.EntriesTotal );
                this.UIThread(() => progressBar2.Value = e.EntriesSaved + 1 );
            else if (e.EventType == ZipProgressEventType.Saving_EntryBytesRead)
                this.UIThread(() => progressBar1.Value = (int)((e.BytesTransferred * 100) / e.TotalBytesToTransfer));
                    () => label6.Text = e.BytesTransferred.ToString() + " / " + e.TotalBytesToTransfer.ToString()
            else if (e.EventType == ZipProgressEventType.Saving_Completed)
                //MessageBox.Show("Done: " + e.ArchiveName);


Are you talking about something different? I'm not sure how I would set the backgroundworker's EVent to "Cancel" within this method?

Apr 15, 2011 at 10:35 PM
Edited Apr 15, 2011 at 10:37 PM

Can you show more of your code?  What you're doing is not clear from what you have shown so far.

In your first post, the "if (worker.CancellationPending)" statement, is inappropriate.  I think.  I don't see a zippy.Save() call, but normally you would want to cancel OUT of the context of the Save(). 

What happens is this: your application creates a zipfile object, adds some file and directory entries to the object, then calls Save() on the ZipFile object.

Within the context of that call to Save(), the DotNetZip library calls back into your SaveProgress() method, periodically, via the event mechanism in .NET.   It is within the your SaveProgress() code that you have the chance to cancel a Save, if you so desire, by setting e.Cancel to true.  You cannot cancel a Save from the code that runs BEFORE you call ZipFile.Save(). 

You can certainly look for cancellation requests before you call ZipFile.Save().  But normally, a very small amount of time (maybe 1%) is spent adding entries into the ZipFile, and the large majority of the time is spent in the call to Save(), reading and compressing those entries, and  writing the output.  so, it is often ineffectual to look for and respond to cancellation, before invoking ZipFile.Save().

Apr 18, 2011 at 4:09 PM

That is the winform code. If I'm understanding you correctly, I can just set "e.Cancel" in the SaveProgress event handler? Does this mean I should just use some sort of variable to cancel the saveprogress rather than checking if the Worker thread is is "canceled" and let the thread run through?

Apr 18, 2011 at 5:41 PM

Yes, normally you'd set a variable tracking whether cancellation was requested, in the "Click" event handler for a "cancel" button.  Let's call that variable cancelRequestPending.

Then, in the SaveProgress event, test that cancelRequestPending variable, and if it is true, then set e.Cancel to true.

When that particular invocation of SaveProgress() returns, DotNetZip will check the e.Cancel field, and will stop its saving work if it has been set.  If e.Cancel is not true, then DotNetZip will just keep working, and will invoke your SaveProgress() again and again, as appropriate.