Yes, you can! (create mutifile zip files in .NET Framework (finally))

I recently have been working on moving some projects from an old legacy build system to a new shiny build system. After understanding intricacies of the old build system I was able to isolate and remove 99% stuff we did not really need and comment out the remaining 1% we needed but could not make it work easily. I felt proud of myself because I was even able to build something in the new build system (OK, maybe the stuff we did not need was actually 98.9%?). So, I started uncommenting things we needed but were not as straightforward to fix. One of the first things I came across was the need of zipping files after building. I thought I would just use the MSBuild Zip task and call it done. Unfortunately it turned out that out of the box MSBuild does not have a Zip task. I could find it in MSBuild community tasks but for certain reasons we could not take a dependency on these. We also did not have a zip-like command line tool we could take a dependency on. One of the last sunny days around Seattle this year started looking gloomy to me. I asked folks on our team and they had a few ideas like using PowerShell (we don’t really need it anywhere else so again I wanted to avoid it), leveraging a third party library we could use to create a task or finally using GZipStream. I liked the idea of using GZipStream – I could create and inline MSBuild task which would be clean and simple. However gzip only supports compressing one file and I needed to zip several files so, I could not use it. I spent more time looking for something suitable and thought I found it – ZipPackage!. Again, my hopes were quickly dashed. This guy needs a metadata file containing content types of the included files. This file is then added to the archive. But I needed just a POZF™ (Plain Old Zip File) without any additional crap inside! Afternoon was getting really dark. I started looking at the option of using a third party library. It would add complexity to the build system. I would have to build tools before building projects. Suddenly, I had this feeling that instead of having a lightweight, easy and fast build we will have a new version of what we had before. Each time I wanted to start working on this my hands refused and decided to open a browser and check the news or something along these lines. So, I gave one more shot at finding a better solution but I could only find that there is an MSBuild Zip task in the community tasks and that the GZipStream basically can compress only one file and that the ZipPackage requires some metadata. I was loosing hope when suddenly on Xth page of results (where X > 5) I found this – the ZipArchive class. The ZipArchive is a new class in the .NET Framework 4.5 that allows creating zip files containing not only multiple files but also the whole folder hierarchy! In just one second all the clouds were gone. If there had not been for pierogi I would have probably stayed playing with this class until my MSBuild problem was resolved. On the other hand I don’t like when pierogi are too hot so I stayed a few more minutes just to see if it was easy to create a zip file. Here is what I came up with (I checked only briefly but could not find an example how to create a new archive on msdn):

public static void Main()
{
    Zip(
        new string[] 
        { 
            @"C:\Temp\file1.txt", 
            @"C:\temp\file2.txt", 
            @"C:\Source\ConsoleApplication1\ConsoleApplication1\Program.cs" 
        },
        @"c:\temp\out.zip");
}

static void Zip(string[] inputFileNames, string outputFileName)
{
    using (var outputFileStream = new FileStream(outputFileName, FileMode.Create))
    {
        using (var archive = new ZipArchive(outputFileStream, ZipArchiveMode.Create))
        {
            foreach (var inputFile in inputFileNames)
            {
                AddFileToArchive(archive, inputFile);
            }
        }
    }
}

static void AddFileToArchive(ZipArchive archive, string inputFile)
{
    const int BufferSize = 64 * 1024;

    // relies on inputFile being an absolute path 
    // - Substring(3) removes :\ from the path
    var archiveEntry = archive.CreateEntry(inputFile.Substring(3));

    using (var fs = new FileStream(inputFile, FileMode.Open))
    {
        using (var zipStream = archiveEntry.Open())
        {
            byte[] buffer = new byte[BufferSize];
            int bytesRead = -1;
            while ((bytesRead = fs.Read(buffer, 0, BufferSize)) > 0)
            {
                zipStream.Write(buffer, 0, bytesRead);
            }
        }
    }
}

I can open the archive I created in the Windows Explorer, browse and open files. No additional metadata files are added to the archive – it’s a POZF™. So – yes, you now can create a multifile zip archives in .NET Framework without using third party libraries. And now creating an inline MSBuild Zip task that fits my new build system is easy. This makes me happy!

Pawel Kadluczka

Advertisement

5 thoughts on “Yes, you can! (create mutifile zip files in .NET Framework (finally))

  1. xyzzer says:

    Cool. 🙂 I’m slowly beginning to miss the full .NET Framework. 🙂

    Liked by 1 person

    • moozzyk says:

      It has some handy classes, indeed. OTOH it is so big that sometimes you don’t really know what you have (vide ZipArchive) – especially if it was hidden in the Intellisense or a reference is missing…

      Like

      • xyzzer says:

        Yeah, it’s nice that with WinRT you have EVERYTHING referenced. That is unless your method is in your own separate assembly you forgot to reference… 😀

        Like

  2. Thankyou for this post! I wasn’t aware of this, but now that I am, its happy times 😉

    Like

  3. […] build”? I don’t think it’s OK, but before I could not help much. Fortunately, a Zip library was finally added to .NET Framework 4.5. This allowed me creating my own Zip task. How is this task different from, for instance, the Zip […]

    Like

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 )

Facebook photo

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

Connecting to %s

%d bloggers like this: