Thursday, May 19, 2005

Lately, people have been asking us how to abort a zipping operation with Xceed Zip for .NET. The official answer is "you can't", as there is no method or property exposed for this task, as opposed to Xceed Zip ActiveX with its simple Abort property. But the truth is you can, with relatively little coding.

Before we get into how to abort, let's talk a little bit about the ZipArchive's TempFolder property. By default, it points to the same folder as the static ZipArchive.DefaultTempFolder property, which itself points to the user's temp folder, as exposed by System.IO.Path.GetTempPath().

Though the library is designed to delete any file it creates in the temporary folder, this can occur only when instances get finalized if the operation failed in the middle of the process.

A good coding pattern I like to use is the following:

    ZipArchive zip = new ZipArchive( new DiskFile( @"d:\temp\backup.zip" ) );
    zip.TempFolder = zip.TempFolder.CreateFolder( Guid.NewGuid().ToString() );
 
    try
    {
      using( AutoBatchUpdate auto = new AutoBatchUpdate( zip ) )
      {
        DiskFolder source = new DiskFolder( @"d:\Data" );
        source.CopyTo( zip, true );
      }
    }
    finally
    {
      zip.TempFolder.Delete();
    }

This makes sure no temp file survive a zipping cycle. And with that pattern, I can set the "default" temporary location once using the static DefaultTempFolder property, and each instance will use a unique folder within this starting point.

Now that my zipping operations are cleaning their traces, we're ready to talk about aborting. Some key concepts:

  • The library isn't pumping messages, and does not offer async operations. If you want your WinForms application's "Abort" button to react, you will have to pump messages yourself somewhere.
  • There are three major operations behind the creation or modification of a zip file:
    • Compressing each new file.
    • Moving each file to keep from the original zip file (if updating an existing zip file).
    • Building the target zip file by appending data created by the above two steps.
  • Zip and FileSystem events get raised at many levels, so you should pass your ZipEvents instance everywhere an overload accepting a FileSystemEvents or ZipEvents instance exists.

Your "Abort" button (or any abort input you like) will simply raise a flag. It can't do more.

    private bool m_abort = false;
 
    private void AbortButton_Click(object sender, System.EventArgs e)
    {
      m_abort = true;
    }

Then you handle three events matching the forementioned three steps, pump messages to keep a responsive application, and check if the flag is raised. You can safely use the same method for handling the three events.

    private void CheckAbort_ByteProgression(object sender, ByteProgressionEventArgs e)
    {
      if( m_abort )
        throw new ApplicationException( "The user aborted the operation." );
 
      Application.DoEvents();
    }

As you can see, if the flag is raised, I'm throwing an ApplicationException. This will result in a System.Reflection.TargetInvocationException being thrown by the originally called method. To get a well-behaved application, you obviously want to trap any exception the FileSystem could throw. You can catch any TargetInvocationException to display an "operation aborted" message. Here's my code for the full operation:

    private void StartButton_Click(object sender, System.EventArgs e)
    {
      m_abort = false;
      StartButton.Enabled = false;
      AbortButton.Enabled = true;
 
      try
      {
        ZipEvents events = new ZipEvents();
 
        // Advise for the three main events for checking abort flag.
        events.ByteProgression += 
          new ByteProgressionEventHandler( CheckAbort_ByteProgression );
        events.GatheringZipContentByteProgression += 
          new GatheringZipContentByteProgressionEventHandler( CheckAbort_ByteProgression );
        events.BuildingZipByteProgression += 
          new BuildingZipByteProgressionEventHandler( CheckAbort_ByteProgression );
 
        // What's cool with delegates is that you can separate logic from UI.
        events.ByteProgression += 
          new ByteProgressionEventHandler( UpdateUI_ByteProgression );
 
        ZipArchive zip = new ZipArchive( 
          events, null, new DiskFile( @"d:\temp\backup.zip" ) );
 
        zip.TempFolder = zip.TempFolder.CreateFolder( Guid.NewGuid().ToString() );
 
        try
        {
          using( AutoBatchUpdate auto = new AutoBatchUpdate( zip, events, null ) )
          {
            DiskFolder source = new DiskFolder( @"d:\Data" );
            source.CopyTo( events, null, zip, true );
          }
        }
        finally
        {
          zip.TempFolder.Delete();
 
          // Clean up events.
          events.ByteProgression -= 
            new ByteProgressionEventHandler( CheckAbort_ByteProgression );
          events.GatheringZipContentByteProgression -= 
            new GatheringZipContentByteProgressionEventHandler( CheckAbort_ByteProgression );
          events.BuildingZipByteProgression -= 
            new BuildingZipByteProgressionEventHandler( CheckAbort_ByteProgression );
 
          events.ByteProgression -= 
            new ByteProgressionEventHandler( UpdateUI_ByteProgression );
        }
      }
      catch( System.Reflection.TargetInvocationException except )
      {
        MessageBox.Show( except.InnerException.Message, "Abort" );
      }
      catch( Exception except )
      {
        MessageBox.Show( except.Message, "Error" );
      }
      finally
      {
        AbortButton.Enabled = false;
        StartButton.Enabled = true;
        m_abort = false;
      }
    }

Things to notice:

  • I'm passing my "events" instance to:
    • The ZipArchive's ctor. You could handle the ReadingZipItemProgression events.
    • The AutoBatchUpdate ctor, which will in turn pass it to both BeginUpdate and EndUpdate. The later method will generate the GatheringZipContentByteProgression and BuildingZipByteProgression events.
    • The CopyTo method. It will generate the ByteProgression events.
  • I'm advising two times for the ByteProgression events, once for handling abort conditions, and another for updating my UI. This is a cool way to leverage delegates and separate the logic from the UI.

.NET | Zip

5/19/2005 4:53:12 PM (Eastern Daylight Time, UTC-04:00)  #   
Tracked by:
"revlon" (revlon) [Trackback]
"sesso in macchina" (sesso in macchina) [Trackback]
"grandezza orgia a 3" (grandezza orgia a 3) [Trackback]
"march 1976 playboy" (march 1976 playboy) [Trackback]
"modesto estreme" (modesto estreme) [Trackback]
"lee ryan" (lee ryan) [Trackback]
"teen" (teen) [Trackback]
"rich bitch hates blackmen" (rich bitch hates blackmen) [Trackback]
"posizione fare amore" (posizione fare amore) [Trackback]
"xxx audition" (xxx audition) [Trackback]
"bello fighette fotti" (bello fighette fotti) [Trackback]
"wild college girls flashing" (wild college girls flashing) [Trackback]
"megatettone" (megatettone) [Trackback]
"massage therapy schools in citrus heights" (massage therapy schools in citrus h... [Trackback]
"amateur multiple facial shots" (amateur multiple facial shots) [Trackback]
"sleeping upskirt" (sleeping upskirt) [Trackback]
"computer grafica" (computer grafica) [Trackback]
"lesbian fondling teens" (lesbian fondling teens) [Trackback]
"erotic dating sims" (erotic dating sims) [Trackback]
"figc cru" (figc cru) [Trackback]
"controllo di gestione" (controllo di gestione) [Trackback]
"sindrome" (sindrome) [Trackback]
"musica mp3 gratis" (musica mp3 gratis) [Trackback]
"boca raton beach hotels" (boca raton beach hotels) [Trackback]
"elk grove herald march 6%2c 2006" (elk grove herald march 6%2c 2006) [Trackback]
"arredamento negozi abbigliamento" (arredamento negozi abbigliamento) [Trackback]
"dirty hip hop images" (dirty hip hop images) [Trackback]
"hot bitches big asses tits" (hot bitches big asses tits) [Trackback]
"ore boat canadian challenger" (ore boat canadian challenger) [Trackback]
"prenotazione vacanza" (prenotazione vacanza) [Trackback]
"big butt tight jeans" (big butt tight jeans) [Trackback]
"legge fallimentare" (legge fallimentare) [Trackback]
"female athletes posing" (female athletes posing) [Trackback]