Zip / Unzip folders and files with C#


By Peter Bromberg
Printer Friendly Version
  

The .NET Framework includes GZipStream and related classes, but they only support compression, not the standard ZIP file structure. This article explains how you can handle correctly zipping and unzipping folders and files including using a zip password.



A-well-a don't you know about the bird?
Well, everybody knows that the bird is the word!  --
The Trashmen (1963)

The .NET Framework has GzipStream and DeflateStream classes for compression tasks, but they do not support the standard ZIP file / folder FileEntry mechanism to zip a folder with all its files and subfolders.

Fortunately, the ICSharpCode SharpZipLib project does support this, as well as passwords for zip files and compression level.

Here is a utility class I wrote that handles zipping or unzipping a folder with all its subfolders and contained files, using SharpZipLib:

 

using System;
using System.Collections;
using System.IO;
using ICSharpCode.SharpZipLib.Zip;

namespace FolderZipper
{
    public static class ZipUtil
    {
        public static void ZipFiles(string inputFolderPath, string outputPathAndFile, string password)
        {
            ArrayList ar = GenerateFileList(inputFolderPath); // generate file list
            int TrimLength = (Directory.GetParent(inputFolderPath)).ToString().Length;
            // find number of chars to remove     // from orginal file path
            TrimLength += 1; //remove '\'
            FileStream ostream;
            byte[] obuffer;
            string outPath = inputFolderPath + @"\" + outputPathAndFile;
            ZipOutputStream oZipStream = new ZipOutputStream(File.Create(outPath)); // create zip stream
            if (password != null && password != String.Empty)
                oZipStream.Password = password;
            oZipStream.SetLevel(9); // maximum compression
            ZipEntry oZipEntry;
            foreach (string Fil in ar) // for each file, generate a zipentry
            {
                oZipEntry = new ZipEntry(Fil.Remove(0, TrimLength));
                oZipStream.PutNextEntry(oZipEntry);

                if (!Fil.EndsWith(@"/")) // if a file ends with '/' its a directory
                {
                    ostream = File.OpenRead(Fil);
                    obuffer = new byte[ostream.Length];
                    ostream.Read(obuffer, 0, obuffer.Length);
                    oZipStream.Write(obuffer, 0, obuffer.Length);
                }
            }
            oZipStream.Finish();
            oZipStream.Close();
        }


        private static ArrayList GenerateFileList(string Dir)
        {
            ArrayList fils = new ArrayList();
            bool Empty = true;
            foreach (string file in Directory.GetFiles(Dir)) // add each file in directory
            {
                fils.Add(file);
                Empty = false;
            }

            if (Empty)
            {
                if (Directory.GetDirectories(Dir).Length == 0)
                    // if directory is completely empty, add it
                {
                    fils.Add(Dir + @"/");
                }
            }

            foreach (string dirs in Directory.GetDirectories(Dir)) // recursive
            {
                foreach (object obj in GenerateFileList(dirs))
                {
                    fils.Add(obj);
                }
            }
            return fils; // return file list
        }


        public static void UnZipFiles(string zipPathAndFile, string outputFolder, string password, bool deleteZipFile)
        {
            ZipInputStream s = new ZipInputStream(File.OpenRead(zipPathAndFile));
            if (password != null && password != String.Empty)
                s.Password = password;
            ZipEntry theEntry;
            string tmpEntry = String.Empty;
            while ((theEntry = s.GetNextEntry()) != null)
            {
                string directoryName = outputFolder;
                string fileName = Path.GetFileName(theEntry.Name);
                // create directory 
                if (directoryName != "")
                {
                    Directory.CreateDirectory(directoryName);
                }
                if (fileName != String.Empty)
                {
                    if (theEntry.Name.IndexOf(".ini") < 0)
                    {
                        string fullPath = directoryName + "\\" + theEntry.Name;
                        fullPath = fullPath.Replace("\\ ", "\\");
                        string fullDirPath = Path.GetDirectoryName(fullPath);
                        if (!Directory.Exists(fullDirPath)) Directory.CreateDirectory(fullDirPath);
                        FileStream streamWriter = File.Create(fullPath);
                        int size = 2048;
                        byte[] data = new byte[2048];
                        while (true)
                        {
                            size = s.Read(data, 0, data.Length);
                            if (size > 0)
                            {
                                streamWriter.Write(data, 0, size);
                            }
                            else
                            {
                                break;
                            }
                        }
                        streamWriter.Close();
                    }
                }
            }
            s.Close();
            if (deleteZipFile)
                File.Delete(zipPathAndFile);
        }
    }
}
You can dowload the Visual Studio 2008 Solution, which includes a Windows Forms "Tester" app that allows you to test the class library. Note that I have not included any validation on the various textboxes, File and Folderbrowser dialogs. If you do not have Visual Studio 2008, just make a new blank solution and add the project files to it.


Biography
Peter Bromberg is a C# MVP, MCP, and .NET expert who has worked in banking ,financial and telephony for 20 years. Pete focuses exclusively on the .NET Platform, and his samples at GotDotNet.com have been downloaded over 56,000 times. Peter enjoys producing 3D raytraced digital photo collage with Maya, the beach, and fine wines. You can view Peter's UnBlogIttyUrl, and BlogMetafinder sites.
Please post questions at forums, not via email!

button

 
Article Discussion: Zip / Unzip folders and files with C#
Peter Bromberg posted at 04-Feb-08 12:01
Original Article

 
Cleanup
Drew Miller replied to Peter Bromberg at 02-Apr-08 10:32
It seems prudent to me to wrap both the ZipOutputStream and FileStream with using statements, to ensure that the code is being properly disposed of.  Maybe I'm just overly cautious though ^_^

 
Framework 2.0
Doug Odegaard replied to Peter Bromberg at 21-Feb-08 03:16

Peter,

If I understand you correctly the standard framework libraries do not allow creating of ZIP files themselves but only compression in the life of the app.  Correct?  So SharpZipLib is the best alternative in your opinion?  I need to take photos and files in an ASP.NET app from a database and combine in a zip file for download to the user.  Thanks in advance.

Doug - Missoula, MT


 
How to use this "utility class" to zip and store one excel file?
Ashok kumar replied to Peter Bromberg at 14-Feb-08 05:33

Hi Pete,
Subject: Regarding "How to zip one excel file with the given utility class".

Thankyou very much since you have given one very beautiful article. But I could not understand how to use this utility class to zip and store one excel file.
My concern is:
01. How to zip one excel file with the given utility class?
02. How to store the .zipped file at one location?

Kind Regards,
Ashok kumar.
Software Engineer from Bangalore/India.


 
If you want to zip and store one Excel file
Peter Bromberg replied to Ashok kumar at 02-Mar-08 07:47
you can either use the technique outlined in the article, or just use the compression classes. The standard Zip folder / file header structure as outlined in the article is considered the standard way to build a Zip file, even if it's only contents is a single Excel workbook.

 
Correct.
Peter Bromberg replied to Doug Odegaard at 02-Mar-08 07:45
The .NET 2.0 Deflate and GZip stream classes only support compression. To make a zip file that is compatible with say, WinZip, you need to be able to create the zip headers that define the file and folder structure. SharpZipLib does this.

 
DotNetZip
Doug Odegaard replied to Peter Bromberg at 13-Mar-08 09:25

See this posting at Codeplex to help with this as of late

http://weblogs.asp.net/jgalloway/archive/2007/10/25/creating-zip-archives-in-net-without-an-external-library-like-sharpziplib.aspx