DevPinoy.org
A Filipino Developers Community
   
How To: Create Zip Files In C# with SharpZipLib (#ZipLib)

I encountered a problem today with one of my projects. The problem was about a third-party application choking when it encounters files greater than 20MB. I have a Windows Service that creates PDFs of KPIs for around 150 users and each of the file that I generate is around 25MB each. I can compress the PDF file to lower resolution format but the management decided that we shouldn't trade quality over speed so I was stuck thinking of a different solution.

Then it came to me that I can zip the files so that I get a smaller file.

I started evaluating C# zip libraries and ended up choosing #ZipLib from the creators of SharpDevelop because of it's simplicity and robustness. The only thing I didn't like was the fact that I wasn't find a great documentation about the library. I ended up fiddling with it. It wasn't hard but you need to play with it alot to understand whats happening in the background.

Ok, now lets start by identifying what we need to create a zip file with SharpZipLib. The first thing that you need to do is download the binaries from the #ZipLib website and reference that DLL in your project.

Now that is done you need to add the ICSharpCode.SharpZipLib namespace in you source file to be able to start creating zip files using the #ZipLib library.

To start creating a zip file, all you need to do is to initialize a ZipFile object.

//initialize the file so that it can accept updates
ZipFile z = ZipFile.Create(filename);

The code above creates a new zip file with the specified filename. Next we need to call the BeginUpdate method of the ZipFile object to tell it that we are going to do some modifications to that file.

//initialize the file so that it can accept updates
z.BeginUpdate();

At this stage we can now add files to our zip file.

//add your file e.g "c:\reports\gummywhammyyummy.pdf"
z.Add(<Your file to add including it's path>);

Once you are done you need to commit  your changes and close the file.

//commit the update once we are done
z.CommitUpdate();
//close the file
z.Close();

Done. Now you have created your first zip file using #ZipLib. Neat! Below is the complete code listing of what we did above

/// <summary>
/// A method that creates a zip file
/// </summary>
/// <param name="zipFileStoragePath">the storage location</param>
/// <param name="zipFileName">the zip file name</param>
/// <param name="fileToCompress">the file to compress</param>
private void CreateZipFile(string zipFileStoragePath
    , string zipFileName
    , string fileToCompress)
{
    //create our zip file
    ZipFile z = ZipFile.Create(zipFileStoragePath + zipFileName);

    //initialize the file so that it can accept updates
    z.BeginUpdate();

    //add the file to the zip file
    z.Add(fileToCompress);

    //commit the update once we are done
    z.CommitUpdate();
    //close the file
    z.Close();
}

But what if you want to add a directory to your zip file? The ZipFile object provides a method called AddDirectory() that accepts a parameter directoryName. The problem with this method is that it doesn't add the files inside the specified directory but instead just creates a directory inside the zip file. To make this work, you need to get the files inside that directory by looping thru all objects in that directory and adding them one at a time. I was able to accomplish this task by creating a recursive function that drills through the whole directory structure of the folder you want to zip. Below is a snippet of the function.

/// <summary>
/// Creates a zip file
/// </summary>
/// <param name="zipFileStoragePath">where to store the zip file</param>
/// <param name="zipFileName">the zip file filename</param>
/// <param name="fileToZip">the file to zip</param>
/// <returns>indicates whether the file was created successfully</returns>
private bool CreateZipFile(string zipFileStoragePath
    , string zipFileName
    , FileInfo fileToZip)
{
    return CreateZipFile(   zipFileStoragePath
                        ,   zipFileName
                        ,   (FileSystemInfo)fileToZip);
}

/// <summary>
/// Creates a zip file
/// </summary>
/// <param name="zipFileStoragePath">where to store the zip file</param>
/// <param name="zipFileName">the zip file filename</param>
/// <param name="directoryToZip">the directory to zip</param>
/// <returns>indicates whether the file was created successfully</returns>
private bool CreateZipFile(string zipFileStoragePath
    , string zipFileName
    , DirectoryInfo directoryToZip)
{
    return CreateZipFile(   zipFileStoragePath
                        ,   zipFileName
                        ,   (FileSystemInfo)directoryToZip);
}

/// <summary>
/// Creates a zip file
/// </summary>
/// <param name="zipFileStoragePath">where to store the zip file</param>
/// <param name="zipFileName">the zip file filename</param>
/// <param name="fileSystemInfoToZip">the directory/file to zip</param>
/// <returns>indicates whether the file was created successfully</returns>
private bool CreateZipFile(string zipFileStoragePath
    , string zipFileName
    , FileSystemInfo fileSystemInfoToZip)
{
    return CreateZipFile(   zipFileStoragePath
                        ,   zipFileName
                        ,   new FileSystemInfo[] 
                            { 
                                fileSystemInfoToZip 
                            });
}

/// <summary>
/// A function that creates a zip file
/// </summary>
/// <param name="zipFileStoragePath">location where the file should be created</param>
/// <param name="zipFileName">the filename of the zip file</param>
/// <param name="fileSystemInfosToZip">an array of filesysteminfos that needs to be added to the file</param>
/// <returns>a bool value that indicates whether the file was created</returns>
private bool CreateZipFile(string zipFileStoragePath
    , string zipFileName
    , FileSystemInfo[] fileSystemInfosToZip)
{
    // a bool variable that says whether or not the file was created
    bool isCreated = false;

    try
    {
        //create our zip file
        ZipFile z = ZipFile.Create(zipFileStoragePath + zipFileName);
        //initialize the file so that it can accept updates
        z.BeginUpdate();
        //get all the files and directory to zip
        GetFilesToZip(fileSystemInfosToZip, z);
        //commit the update once we are done
        z.CommitUpdate();
        //close the file
        z.Close();
        //success!
        isCreated = true;
    }
    catch (Exception ex)
    {
        //failed
        isCreated = false;
        //lets throw our error
        throw ex;
    }
 
    //return the creation status
    return isCreated;
}

/// <summary>
/// Iterate thru all the filesysteminfo objects and add it to our zip file
/// </summary>
/// <param name="fileSystemInfosToZip">a collection of files/directores</param>
/// <param name="z">our existing ZipFile object</param>
private void GetFilesToZip(FileSystemInfo[] fileSystemInfosToZip, ZipFile z)
{
    //check whether the objects are null
    if (fileSystemInfosToZip != null && z != null)
    {
        //iterate thru all the filesystem info objects
        foreach (FileSystemInfo fi in fileSystemInfosToZip)
        {
            //check if it is a directory
            if (fi is DirectoryInfo)
            {
                DirectoryInfo di = (DirectoryInfo)fi;
                //add the directory
                z.AddDirectory(di.FullName);
                //drill thru the directory to get all
                //the files and folders inside it.
                GetFilesToZip(di.GetFileSystemInfos(), z);
            }
            else
            {
                //add it
                z.Add(fi.FullName);
            }
        }
    }
}

A sample usage of this function would be like this:

//sample usage for zipping a file
private void zipItButton_Click(object sender, EventArgs e)
{
    string fileToZip = fileToZipTextBox.Text;
    string zipFilename = Guid.NewGuid() + ".zip";

    //zip a file
    bool isCreated = CreateZipFile(
                                        CONST_ZIP_FILE_STORAGE
                                    ,   zipFilename
                                    ,   new FileInfo(fileToZip) );

    if (isCreated) {
        MessageBox.Show(zipFilename);
    }
    else {
        MessageBox.Show("Failed");
    }
}

//sample usage for zipping a directory
private void zipFolderButton_Click(object sender, EventArgs e)
{
    string directoryToZip = whereToZipTextBox.Text;
    string zipFilename = Guid.NewGuid() + ".zip";

    //zip a directory
    bool isCreated = CreateZipFile(
                            CONST_ZIP_FILE_STORAGE
                        , zipFilename
                        , new DirectoryInfo(directoryToZip) );

    if (isCreated){
        MessageBox.Show("Created " + zipFilename);
    }
    else{
        MessageBox.Show("Failed");
    }
}

And that's it. I hope i was able to shed light on you can create zip files in few easy steps with C#.

If you are interested you can checkout this sample application that I built to demonstrate how to create zip files with C# and SharpZipLib.

Download the source code here. KeithRull.CreatingZipFiles.zip (19.15 KB)


Posted 01-25-2008 2:01 PM by keithrull
Filed under: , , ,

Comments

cruizer wrote re: How To: Create Zip Files In C# with SharpZipLib (#ZipLib)
on 01-25-2008 6:12 PM

this is awesome keith :)

keithrull wrote re: How To: Create Zip Files In C# with SharpZipLib (#ZipLib)
on 01-28-2008 11:13 AM

Thanks Cruizer :)

Allan Rees wrote re: How To: Create Zip Files In C# with SharpZipLib (#ZipLib)
on 03-25-2008 6:47 AM

Any advice on doing it all in memory, ie not reading from a disk or writing to a disk, rather email the zip to someone

Snorkel wrote re: How To: Create Zip Files In C# with SharpZipLib (#ZipLib)
on 06-23-2008 12:35 PM

anyone know how to do the equivelent of:

zip -A sfx.exe

To create a self extractor after combining the stub and the resulting zip file?

Knot wrote re: How To: Create Zip Files In C# with SharpZipLib (#ZipLib)
on 08-27-2008 9:57 AM

Thank you. Awesome way to explain usage while keeping to the KISS approach.

Princy wrote re: How To: Create Zip Files In C# with SharpZipLib (#ZipLib)
on 08-30-2008 9:28 PM

The code is awesome.

But its creating the complete folder structure of the input file inside the zip file. How to avoid that..? somebody help me..

Padmanaban wrote re: How To: Create Zip Files In C# with SharpZipLib (#ZipLib)
on 09-04-2008 1:17 AM

how can create zip in stream and add files (byte[]) to this stream

Nishant Garg wrote re: How To: Create Zip Files In C# with SharpZipLib (#ZipLib)
on 11-16-2008 9:09 PM

Great thing and thanks

Adam Carlson wrote re: How To: Create Zip Files In C# with SharpZipLib (#ZipLib)
on 11-20-2008 1:41 PM

@Padmanaban: I'd love to know how to do the same thing. I tried the ZipOutputSteam object's "Read()" method but I got an exception saying it is not supported.

As far as I can see, a ZipEntry() object needs to be created and its constructor only accepts a string (path to file on disk).

cvega wrote re: How To: Create Zip Files In C# with SharpZipLib (#ZipLib)
on 11-20-2008 9:14 PM

Hi Adam,

Try this:

static byte[] Compress(byte[] bytes) {

 MemoryStream memory = new MemoryStream();

 object stream = new Zip.Streams.DeflaterOutputStream(memory,

   new Zip.Deflater(Zip.Deflater.BEST_COMPRESSION), 131072);

 stream.Write(bytes, 0, bytes.Length);

 stream.Close();

 return memory.ToArray();

}

static byte[] Decompress(byte[] bytes) {

 object stream = new Zip.Streams.InflaterInputStream(

                 new MemoryStream(bytes));

 MemoryStream memory = new MemoryStream();

 byte[,] writeData;

 int size;

 while (true) {

   size = stream.Read(writeData, 0, writeData.Length);

   if ((size > 0)) {

     memory.Write(writeData, 0, size);

   }

   else {

     break;

   }

 }

 stream.Close();

 return memory.ToArray();

}

cvega wrote re: How To: Create Zip Files In C# with SharpZipLib (#ZipLib)
on 11-20-2008 9:19 PM

Snorkel,

You need to create a self-extracting stub, then embed both your stub and zipped directory to a single file.

There's nothing in the library to create a self-extracting stub, you have to create this manually.

You can find several example in codeproject.

modchip wrote re: How To: Create Zip Files In C# with SharpZipLib (#ZipLib)
on 11-20-2008 10:58 PM

OMG! This is awesome! Nice job boss Keith!

axion wrote re: How To: Create Zip Files In C# with SharpZipLib (#ZipLib)
on 05-05-2009 2:12 PM

Hey there - this tutorial is very nice. however i'm trying to zip the files without the folders they were in. I've tried passing it only the files but obviously that didnt work. it needs the full path when I 'add'.

Is there a way to remove the relative paths to each file inside the zip? (i'm trying to make them all available in the root of the zip so i dont have do go in each directory to get to them)

Let me know, hope to get a reply. thanks!

smitty2 wrote re: How To: Create Zip Files In C# with SharpZipLib (#ZipLib)
on 11-13-2009 4:16 PM

to fix the directory structure issue (where you extract a ZIP and it builds the entire directory structure to the original file path you zipped), use the other overload for AddFile():

string ZipOutputFilePath = FilePathNoSuffix + ".zip";

ZipFile z = ZipFile.Create(ZipOutputFilePath);

z.BeginUpdate();

z.Add(FixedPath, Path.GetFileName(FixedPath));

z.CommitUpdate();

z.Close();

This would fix the same scenario that Princy mentioned above.

Copyright DevPinoy 2005-2008