Zipping a directory and including relative directory paths is non-intuitive with DotNetZip

I recently had to write some code to auto-update an application via an FTP server. It uses home-grown code since ClickOnce is too limiting, and is written in a Windows Forms .NET 3.5 Visual Studio 2010 project. It also had to back up existing files before updating, and I was forced to use DotNetZip, which the project already references. (In .NET 4.5 and up, I’d much rather use System.IO.Compression.ZipArchive since I don’t require a password-protected archive. I’ve even written some decent extension methods to read and write zip files asynchronously that way.)

For some reason, when you zip a directory with DotNetZip, by default rather than it using a sensible relative path for each file added, which it could infer from the paths of the files added, when you call the ZipFile.AddDirectory method, it uses the entire hierarchical path structure from the root of the drive. This Stack Overflow answer didn’t solve my problem because it throws away the path info for each file, putting them all in the root of the zip file. I want the recursive path in the zip file entries, just not the whole damn path. This seems to me like a simple requirement, and one I would expect to be supported out of the box. Yet it’s not only unsupported, but also none of the examples on their wiki behave this way.

Here is my solution, which zips everything in the given directory recursively, other than zip files. Rather than adding the directory with a single method-call, it adds the individual files in a loop, and for each file, specifies a directory in the zip file relative to the specified root directory, by simply replacing the root directory part of each path string with an empty string.

Edit: Wrapped the code more so it’s easier to read. It makes this look like more code though… actually it’s very little.

using System.IO;
using System.Linq;
using Ionic.Zip;
using Ionic.Zlib;

namespace Demo
{
    static class Example
    {
        public static void BackupDirectory(string directory)
        {
            using (ZipFile zip = new ZipFile
            {
                CompressionLevel = CompressionLevel.BestCompression
            })
            {
                var files = Directory.GetFiles(directory, "*",
                    SearchOption.AllDirectories).
                    Where(f => Path.GetExtension(f).
                        ToLowerInvariant() != ".zip").ToArray();

                foreach (var f in files)
                {
                    zip.AddFile(f,
                        Path.GetDirectoryName(f).
                        Replace(directory, string.Empty));
                }

                zip.Save(Path.ChangeExtension(directory, ".zip"));
            }
        }
    }
}
Advertisements

About Jerome

I am a senior C# developer in Johannesburg, South Africa. I am also a recovering addict, who spent nearly eight years using methamphetamine. I write on my recovery blog about my lessons learned and sometimes give advice to others who have made similar mistakes, often from my viewpoint as an atheist, and I also write some C# programming articles on my programming blog.
This entry was posted in Programming and tagged , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s