Overwrite a zip archive?

May 23, 2008 at 7:24 PM
I have a zip archive that I would like to create, and want to overwrite the current zip archive.  zip.save(); doesn't seem to do this.  How would I go about overwriting the file?

Any ideas are greatly appreciated.

Thanks Again,
Coordinator
May 24, 2008 at 6:42 PM
The expected behavior of ZipFile.Save() is to overwrite any existing zip archive by the specified name.

I just added a test case to verify that the expected behavior is, in fact, the observed behavior.   It works as advertised.

What behavior or exception do you see?
May 26, 2008 at 12:07 AM
I am not getting any sort of error or anything, but the file is not being overwritten with the new zip.  I just tried this again, and upon inspection of the zip, the new images and files are not contained in the new zip.

Here is my code:

                if (File.Exists(FilePathTB1.Text + @"\Backup.zip"))
                {
                    DialogResult dr = MessageBox.Show("This File Already Exists!  Would You Like To Overwrite It?", "Confirm", MessageBoxButtons.OKCancel);

                    switch (dr)
                    {
                        case DialogResult.Abort:

                            break;

                        case DialogResult.Cancel:
                            // do stuff here.
                            break;

                        case DialogResult.Ignore:

                            break;

                        case DialogResult.No:

                            break;

                        case DialogResult.None:

                            break;

                        case DialogResult.OK:
                            try
                            {
                                using (ZipFile zip = new ZipFile(FilePathTB1.Text + @"\Backup.zip"))
                                {
                                    System.IO.Directory.SetCurrentDirectory(Environment.CurrentDirectory);

                                    ProgressBar1.Visible = true;
                                    Label2.Visible = true;
                                    ProgressBar1.Value = ProgressBar1.Minimum;

                                    //Add the Database File to the zip
                                    zip.AddFile("DB.accdb");
                                    Label2.Text = "Backing up Database...";
                                    ProgressBar1.Increment(20);

                                    //Add the Files Folders and subdirectories to the zip
                                    zip.AddItem("Files");
                                    Label2.Text = "Backing up Files (Images, etc.)...";
                                    ProgressBar1.Increment(70);

                                    //Save the zip
                                    zip.Save();
                                    Label2.Text = "Database and Files Backed Up Successfully!";
                                    ProgressBar1.Increment(10);
                                }
                            }
                            catch
                            {

                            }
                            break;

                        case DialogResult.Retry:

                            break;

                        case DialogResult.Yes:

                            break;

                        default:

                            break;
                    }
                }
Coordinator
May 27, 2008 at 10:40 PM
Edited May 27, 2008 at 11:20 PM
Any chance you could drop a MessageBox.Show() in the Catch { }  clause of your DialogResult.OK case?
Maybe there is an exception occurring that you are swallowing?

One thing - as currently configured, you cannot add a file into the zip, that already exists in the zip. 
So let's say you Create backup.zip, and in it you put a file called "DB.accdb" and a directory called "Files".

Then you update "DB.accdb".  You want to update the Backup.zip with this new content. 
Your code does this: 
  using (ZipFile zip = new ZipFile(FilePathTB1.Text + @"\Backup.zip"))
  {
    zip.AddFile("DB.accdb");
  }

This will throw.  You cannot, with the current Zip Library, call ZipFile.AddFile() using a file that already exists in the Backup.zip. So you cannot call zip.Add("Readme.txt").   If you try this, an exception will be thrown.

The workaround is to create a new zip archive, and overwrite the existing one. 

A reasonable feature request for the DotNetZip library is to allow ZipFile.Add(string Filename) when a file by the name of Filename already exists in the zip archive. 
That seems like a reasonable thing, I'll have to think about how to do it. 

Option 1:
expand the meaning of AddFile() to allow any file, even files already added to the archive?  This seems maybe a little wrong.  It changes the behavior of the existing library, and so may break existing apps.

Option 2:
add a flag to the ZipFile object, named, say, AllowUpdate.  This would explicitly allow the behavior that currently throws an exception.   This would not break existing apps.

Option 3:
add another method, for example ZipFile.UpdateFile().  This also would not break existing apps.

Or I could do a combination of Option 2 & 3.

your vote?
May 28, 2008 at 7:31 AM
Thank you very much for you response.  I will add a catch, and post back with that information. 

With regards to the addition of some form of file overwrite within DotNetZip, I do agree with you on Option 1.  Personally, my preference would probably be Option 3.  As I'm understanding it, it would be something like this, correct:

using (ZipFile zip = new ZipFile.UpdateFile(FilePathTB1.Text + @"\Backup.zip"))

Would this specify ZipFile.UpdateFile and ZipFile.NewFile?  I'm just curious what exactly you have in mind, as I want to make sure I am understanding how you mean.

Thanks Again for an incredible utility.  I will post back with the catch information as soon as possible.

Thanks Again,
Coordinator
May 28, 2008 at 6:54 PM
Edited May 28, 2008 at 7:01 PM

What I am thinking about is this...
You would create a zip file as normal, for example:

      using (ZipFile z1 = new ZipFile())
      {
        String[] filenames = System.IO.Directory.GetFiles("DirectoryToBackup");
        foreach (String f in filenames)        
          z1.AddFile(f, "");        
        z1.Comment = "This archive is a backup";
        z1.Save(ZipFileToCreate);
      }

Then, to update an entry in that zipfile, you might do something like this:

      // update that file in the zip archive
      using (ZipFile z2 = ZipFile.OpenForUpdate(ZipFileToCreate))
      {
        z2.UpdateFile(NameOfFileToUpdate, "");
        z2.Comment = "This backup archive has been updated.";
        z2.Save();
      }

There are two new methods on the ZipFile class here.  First, the OpenForUpdate() static method. It is like the static ZipFile.Read() method, but it opens the ZipFile and allows updates of the entries. (An alternative interface would be to use ZipFile.Read, coupled with a public boolean property, maybe named AllowUpdates.)    The second new method is the ZipFile.UpdateFile() method.  This must be used when adding a file to a zipfile, when an entry using that filename already exists in the zipfile.  [ We need the new method so as to not break the current behavior of AddFile() ]

The code using ZipFile.Read() and AllowUpdates might look like this:

      // update that file in the zip archive
      using (ZipFile z3 = ZipFile.Read(ZipFileToCreate))
      {
        z3.AllowUpdates = true; 
        z3.UpdateFile(NameOfFileToUpdate, "");
        z3.Save();
      }

I have checked in a changeset that does both of these - OpenForUpdate as well as Read + AllowUpdates. I haven't yet uploaded a binary. 

Consider also the removal case.  What if the application wants to remove a file from an existing zip archive?  Though the current (1.4) code does allow adding new entries to a ZipFile, it does not allow removing entries.  So we need a new method like ZipFile.RemoveEntry() for that purpose.

Thinking about this a bit more, it may be that we don't need the AllowUpdates flag, nor the OpenForUpdate() method.   If the only way to Update a file in a zip archive is to call a new API - UpdateFile() -  and the only way to remove an entry from a ZipFile is to call a new API - RemoveEntry()  -  then why not just use the existing static ZipFile.Read() method, and if the app calls these new APIs, allow it?  If the app calls AddFile() with a filename that corresponds to an entry already in the ZipFile, then throw as before.  

It would make for a simpler interface.   The code would then just be:

      // update that file in the zip archive
      using (ZipFile z3 = ZipFile.Read(ZipFileToCreate))
      {
        z3.UpdateFile(NameOfFileToUpdate, "");
        z3.Save();
      }
Coordinator
May 28, 2008 at 7:05 PM

Taking it one step further, maybe what we want is to also introduce a new method AddOrUpdateFile(), which adds the file if it is not present, and updates the file if it is present in the ZipFile.
That would simplify the interface for producing backups.

      // add or update a file in the zip archive
      using (ZipFile z3 = ZipFile.Read(ZipFileToCreate))
      {
        // always works, whether the file already exists in the archive or not
        z3.AddOrUpdateFile(NameOfFileToUpdate, "");
        z3.Save();
      }

and of course, if you want just Update, or just Add, you can just UpdateFile or AddFile too. I'll work on this and produce something later today.

Coordinator
May 28, 2008 at 11:31 PM
OK, Check the preview of Release 1.5 for this capability.   You can now Update entries within a zip file, and you can Remove entries from a zipfile.
Check the doc for example code.

This capability should be fairly solid.

It is classified as a preview release, because I need to add some more stuff to it before it qualifies for a full release. 
May 29, 2008 at 2:41 AM
Cool.  I downloaded and started playing around with the new build.  Does this support AddOrUpdateItem()?  I didn't see this included yet, and things are failing when I try to AddOrUpdateFile on an item ("Files").  It fails with a message that it could not find "Files", which I don't quite understand, and a file in the application directory that I assume is the temporary zip before saving to the selected directory?

Thanks Again.  I am very excited about these changes.
Coordinator
May 29, 2008 at 5:00 PM

There is no AddOrUpdateItem, yet.  I'm working on that.

The garbage file left around in the temp directory - that's an issue with the library. For good hygiene it should clean up its droppings.  I'll file a workitem for that.

 

May 30, 2008 at 5:29 AM
O.K., cool.  I will continue playing around with AddOrUpdateFile, and will play around with AddOrUpdateItem once that is added as well.

It appears if the zip saves with no problems that the garbage file is cleaned up.  But when it fails, the file remains.  I did want to mention though that, for me, the garbage file is not being saved in the temp directory, but in the program directory...  Is this because I am setting the System.IO.Directory.SetCurrentDirectory(Environment.CurrentDirectory); ?  This is probably the case I would imagine...

Thanks Again, I look forward to the addition of AddOrUpdateItem...  :-)
Coordinator
May 30, 2008 at 7:51 AM
Ok, I modified the interface so that there is AddFile AddDirectory AddItem, and UpdateFile UpdateDirectory UpdateItem.

There is no more AddOrUpdateXxxx().   I figure all the capability you want is in UpdateItem(). 


I refreshed the binaries and source for v1.5 of the library.  Try it out. 


The temp file is created in the working directory for the zip library.  This defaults to the current working directory.  You can change it by setting the TempFileFolder on the ZipFile instance. 

I have a workitem to clean up the trash files. 
I haven't done anything with that one yet. 
 
Jun 3, 2008 at 2:18 AM
Alright, I have been playing around with the updated release of 1.5 since its release, and everything seems to be working without any problems whatsoever...  I will continue to play around with this (And any future updates), but did want to post back to let you know that I've had no problems thus far...

Thanks Again.  :)