Compressing and uncompressing ZIP files

Thu 4 January, 2007

For compressing and uncompresing files in ZIP format we have a very valuable tool at our disposal: the SharpZipLib library, made by IC#Code, the same developer group that brought us the awesome Open Source IDE for C# SharpDevelop, which I’ve mentioned before.

First thing we’ve got to do, then, is to download said library to our system. Once donde that, we must include it as a reference on the project we’re using it; and if we believe we’re going to use it somewhat frequently, the comfy option is to install it to the GAC. To do so, let’s open the Visual Studio 2005 Command prompt, located under Tools in the Visual Studio 2005 start menu group. When clicking on it, it opens a new console window and inside it we should go to the folder where we’ve downloaded ICSharpCode.SharpZipLib.dll (for easiness, I have it on a folder of its own at C:\Program Files) and once there we enter the following command:

gacutil /i ICSharpCode.SharpZipLib.dll

Thus we add the library to .NET’s global assembly cache.

So, either if we add the library to the GAC or not, we have to reference it in our project. For it, you know, once our project is created (be it a Console, Windows Forms or Web Forms) whe choose the Project, Add Reference menu item, and we choose the library on the dialog window that opens: on the .NET tab if the library is included in the GAC or we can search it with the tab Browse. Once the reference is included, we add the line


using ICSharpCode.SharpZipLib.Zip;

in our code and we are set to go.
One last disclaimer before gettint to it: to simplify this article I’ve decided for the code examples included to work in the Console and I’ve taken for granted some things like paths and file names. If you want this code to work don’t simply copy and paste it, you’ve got to adapt it to your system and your files.

Listing File Content

Let’s see first how can we list the contents of a ZIP file. for it, we simply declare an object called zip from the class ZipFile. See how SharpZipLib makes a ZipFile composed of ZipEntry objects, not of files or lines or any other thing. The ZipEntry class is going to be any of the entities that can be contained on a ZIP file, files or directories. Once knowing this, we can work our way through the entries on the ZIP file with a foreach loop and we simply show the name of the entry on the Console:

private static void ListZipContent(string sFile) 
{
    ZipFile zip 
= new ZipFile(File.OpenRead(sFile));
    foreach
(ZipEntry entry in zip) 
    {
        Console.WriteLine(entry.Name)
;
    
}

Colorized by: CarlosAg.CodeColorizer

Uncompressing Files

The plot thickens. To uncompress a ZIP file we open it as a ZipInputStream object, we navigate through its entries with the GetNextEntry() method and we save the binary content of each entry on a byte array. Said array will feed a StreamWriter object, which we’ll use to create the new file, which will be an exact uncompressed copy of the binary data stored on the ZIP file’s entry.

private static void UncompressZip(string sFile)
{
    ZipInputStream zipIn 
= new ZipInputStream(File.OpenRead(sFile));
    
ZipEntry entry;
    while 
((entry zipIn.GetNextEntry()) != null)
    {
        FileStream streamWriter 
File.Create(@"C:\Temp\" + entry.Name);
        long 
size entry.Size;
        byte
[] data = new byte[size];
        while 
(true)
        {
            size 
zipIn.Read(data, 0, data.Length);
            if 
(size > 0) streamWriter.Write(data, 0, (int) size);
            else break;
        
}
        streamWriter.Close()
;
    
}
    Console.WriteLine(
"Done!!");

Colorized by: CarlosAg.CodeColorizer

Compressing Files

For compressing files wer’ll use an object similar to the previous one but of the opposite purpose, ZipOutputStream. Wanting to keep this example simple, I’ve supposed we want to compress every existing file on the path passed as parameter sPath. Thus we’ll read all the files sitting on that folder, we’ll create a new ZipEntry object, get some information about the file with FileInfo (we could also use some CRC checking, but I wanted to keep this simple) to assign that information to the new entry, and add the entry to the ZipOutputStream object with its PutNextEntry method. Pay attention, this would create an empty entry: to really enter the data contained in the file we need to read its binary data with a FileStream as in the previous example and then call the method Write from ZipOutputStream to save those binary data on the most recent entry of the output Zip stream. Once read and included all the files, we finish and close the ZipOutputStream object.

private static void CompressZip(string sPath) 
{
    ZipOutputStream zipOut  
= new ZipOutputStream(File.Create(@"C:\Temp\test.zip"));
    foreach
(string fName in Directory.GetFiles(sPath))
    {
        FileInfo fi  
= new FileInfo(fName);
        
ZipEntry entry = new ZipEntry(fi.Name);
        
FileStream sReader File.OpenRead(fName);
        byte
[] buff = new byte[Convert.ToInt32(sReader.Length)];
        
sReader.Read(buff, 0, (int) sReader.Length);
        
entry.DateTime fi.LastWriteTime;
        
entry.Size sReader.Length;
        
sReader.Close();
        
zipOut.PutNextEntry(entry);
        
zipOut.Write(buff, 0, buff.Length);
    
}
    zipOut.Finish()
;
    
zipOut.Close();
    
Console.WriteLine("Done!!");

Colorized by: CarlosAg.CodeColorizer

And this ends this little introduction to SharpZipLib. IC#Code keeps an superb forum on which you can find some more code examples and a lot of answered questions.

Update 5/01/2007.- Playing a little bit with the library and VS 2005’s Object Browser, I stumble upon a class called FastZip. Hmmmmm. Yeah, it’s what it seems: a wrapper class to ease the process of compressing and uncompressing files with SharpZipLib. For example, to uncompress a file it would be as simple as this:

ExtractZip method’s three parameters are strings; and they stand for the name of the ZIP file to uncompress, the destination path for the uncompressed files and a mask for the type of files we want to extract. Warning: you can’t use an DOS mask such as "*.txt", you must use a regular expression. If we want to uncompress every file existing on the path, we should simply leave this last argument as null or empty string "".

private static void FastZipUncompress(string sFile)
{
    FastZip fZip 
= new FastZip();
    
fZip.ExtractZip(sFile, @"C:\Temp""");

Colorized by: CarlosAg.CodeColorizer

And to compress:

private static void FastZipCompress()
{
    FastZip fZip 
= new FastZip();
    
fZip.CreateZip(@"C:\Temp\walls.zip"@"C:\Wallpapers"false".jpg$");
    
Console.WriteLine("Done!!");

Colorized by: CarlosAg.CodeColorizer

In this example the method CreateZip accepts four arguments: the name and path of the ZIP file to be created, the folder where the files we want to compress are, a boolean parameter for stating if we want to make a recursive compression (to include possible subfolders), and last an string parameter specifying the mask we want to use for choosing the files we want to compress, in this example every JPG file. The same rules in using masks applies.

kick it on DotNetKicks.com