Creating Valid ZIP Archives of Multiple Files in C# / .Net

Are .zip files ever going away? I remember back in the 90’s using WinZip as an alternative to the PKZip command line option. Anyway, fast forward 20+ years, and ZIP is still common and a great way to package files. Long story short: AWS Elastic Beanstalk allows you to easily deploy apps using a .zip file (if you haven’t tried Elastic Beanstalk – it’s pretty awesome) and I wanted a faster way to create a .zip of an app. (Yes, I know it’s not the best way to deploy like Git or the API).

There is a bunch of great sample code out there for creating ZIP archives in c# .Net using the ZipArchive Class in System.IO.Compression, but nothing seems to be a complete sample, showing multiple files. Below is what I’ve been using. One difference in this is changing the path separators from backslashes to forward-slashes. Without this, AWS wasn’t able to extract my .zip archive. I would see errors such as:

warning: .... source_bundle appears to use backslashes as path separators
(ElasticBeanstalk::ExternalInvocationError)
(Executor::NonZeroExitStatus)
[Application update ...01_unzip.sh] : Activity failed.

Anyway, here it is:

First, make sure to reference these two:

And at the top of your code file include:

using System.IO;
using System.IO.Compression;

And the basic code is below. Feel free to ask any questions in the comments.

           //what folder to zip - include trailing slash
            string dirRoot = @"c:\yourfolder\";

            //get a list of files
            string[] filesToZip = Directory.GetFiles(dirRoot, "*.*", SearchOption.AllDirectories);

            //final archive name (I use date / time)
            string zipFileName = string.Format("zipfile-{0:yyyy-MM-dd_hh-mm-ss-tt}.zip", DateTime.Now);

            using (MemoryStream zipMS = new MemoryStream())
            {
                using (ZipArchive zipArchive = new ZipArchive(zipMS, ZipArchiveMode.Create, true))
                {
                    //loop through files to add
                    foreach (string fileToZip in filesToZip)
                    {
                        //exclude some files? -I don't want to ZIP other .zips in the folder.
                        if (new FileInfo(fileToZip).Extension == ".zip") continue;

                        //exclude some file names maybe?
                        if (fileToZip.Contains("node_modules")) continue;

                        //read the file bytes
                        byte[] fileToZipBytes = System.IO.File.ReadAllBytes(fileToZip);

                        //create the entry - this is the zipped filename
                        //change slashes - now it's VALID
                        ZipArchiveEntry zipFileEntry = zipArchive.CreateEntry(fileToZip.Replace(dirRoot, "").Replace('\\', '/'));

                        //add the file contents
                        using (Stream zipEntryStream = zipFileEntry.Open())
                        using (BinaryWriter zipFileBinary = new BinaryWriter(zipEntryStream))
                        {
                            zipFileBinary.Write(fileToZipBytes);
                        }

                        //lstLog.Items.Add("zipped: " + fileToZip);
                    }
                }

                using (FileStream finalZipFileStream = new FileStream(@"c:\whateverfolder\Deploy_" + zipFileName, FileMode.Create))
                {
                    zipMS.Seek(0, SeekOrigin.Begin);
                    zipMS.CopyTo(finalZipFileStream);
                }

                //lstLog.Items.Add("ZIP Archive Created.");
            }
Creating Valid ZIP Archives of Multiple Files in C# / .Net

5 thoughts on “Creating Valid ZIP Archives of Multiple Files in C# / .Net

  1. dan says:

    I am curious to know why you didn’t use the CreateEntryFromFile to add your files to the zip file, something like
    foreach (string fileName in todaysFiles) //todaysFiles is list of file names (with full path) to be zipped
    {
    //zipPath is the name of the zip file with full path
    using (ZipArchive archive = ZipFile.Open(zipPath, ZipArchiveMode.Update))
    {
    archive.CreateEntryFromFile(fileName, Path.GetFileName(fileName));
    }
    }

    or what I guess I am really wondering – is the process using streams faster?

    Like

    1. So at first I used this because it was easy, but I found that AWS (EB) didn’t accept the files. I’m not sure why, but I believe it has to do with the handling of files in sub-directories and how their indicated in the .zip file.

      This seemed to be the start of it.
      //change slashes – now it’s VALID
      ZipArchiveEntry zipFileEntry = zipArchive.CreateEntry(fileToZip.Replace(dirRoot, “”).Replace(‘\\’, ‘/’));

      But maybe this works without Stream as well.

      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 )

Twitter picture

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

Facebook photo

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

Connecting to %s