search
Japanese Chinese Nederlands Espanol Italiano Deutsch Francais Twitter Rss Feeds
MicrosoftArticlesForumsFAQs
C# .NET
VB.NET
Visual Studio .NET
ADO.NET
Xml / Xslt
VB 6.0
.NET CF
GDI+
LINQ
Deployment
Security
FoxPro
Silverlight / WPF
Entity Framework
RIA Services

Web ProgrammingArticlesForumsFAQs
JavaScript
ASP
ASP.NET
Web Services

Non-MicrosoftArticlesForumsFAQs
NHibernate
Perl
PHP
Ruby
Java
Linux / Unix
Apple
Open Source

DatabasesArticlesForumsFAQs
SQL Server
Access
Oracle
MySQL
Other Databases

OfficeArticlesForumsFAQs
Excel
Word
Powerpoint
Outlook
Publisher
Money

Operating SystemsArticlesForumsFAQs
Windows 7
Windows Server
Windows Vista
Windows XP
Windows Update
MAC
Linux / UNIX

Server PlatformsArticlesForumsFAQs
BizTalk
Site Server
Exhange Server
IIS

Graphic DesignArticlesForumsFAQs
Macromedia Flash
Adobe PhotoShop
Expression Blend
Expression Design
Expression Web

OtherArticlesForumsFAQs
Subversion / CVS
Ask Dr. Dotnetsky
Active Directory
Networking
Uninstall Virus
Job Openings
Product Reviews
Search Engines
Resumes

 

Zip / Unzip folders and files with C#


By Peter Bromberg
Printer Friendly Version
View My Articles
795 Views
    

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
Peter Bromberg is a C# MVP, MCP, and .NET expert who has worked in banking, financial and telephony for over 20 years. Pete focuses exclusively on the .NET Platform, and currently develops SOA and other .NET applications for a Fortune 500 clientele. Peter enjoys producing digital photo collage with Maya,playing jazz flute, the beach, and fine wines. You can view Peter's UnBlog and IttyUrl sites.
Please post questions at forums, not via email!

button
Article Discussion: Zip / Unzip folders and files with C#
Peter Bromberg posted at Monday, February 04, 2008 12:01 PM
Original Article
 

How to use this "utility class" to zip and store one excel file?
Ashok kumar replied to Peter Bromberg at Thursday, February 14, 2008 5:33 AM

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.

 

Framework 2.0
Doug Odegaard replied to Peter Bromberg at Thursday, February 21, 2008 3:16 PM

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

 

Correct.
Peter Bromberg replied to Doug Odegaard at Sunday, March 02, 2008 7:45 PM
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.
 

If you want to zip and store one Excel file
Peter Bromberg replied to Ashok kumar at Sunday, March 02, 2008 7:47 PM
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.
 

DotNetZip
Doug Odegaard replied to Peter Bromberg at Thursday, March 13, 2008 9:25 AM

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

 

Cleanup
Drew Miller replied to Peter Bromberg at Wednesday, April 02, 2008 10:32 AM
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 ^_^
 

Stream Closing
Ross Killip replied to Drew Miller at Thursday, May 22, 2008 6:42 AM
I agree fully with drew - if for instance you want to zip a folder contents using this awesome bit of code, then delete the original files, to ensure the files are not locked by the zipping process (and thus can't be deleted) you need to ensure the ostream is closed, either by adding the line:ostream.Close(); after the oZipStream.Write(obuffer, 0, obuffer.Length); or by using using statements :)
Nice code snippet though, cheers. :)


                   
             
 

ICSharpCode multiple RAR
padmanaban v replied to Peter Bromberg at Friday, September 05, 2008 4:58 AM
I saw your article on ICSharpCode while searching for code samples to use in our application. I hope you can help me regarding the following scenario.

 

      Now we are done with generating a cryatal report  with CR server XI and exported this to byte[] and decoded to pdf formated base64string. And this base64string will be saved in sql database.

 

      And using asp.net.mail we will send the mail with encoded base64string as attachememt. So the receiver of the mail will be able to open the attachent as PDF.[following this concept to schedule the report]

 

      Here we need your help. Because of constraint of mailing attachemnt size we are searching for possible solution. Is it possible to split the Exported byte[] in to muliple .rar files. And rar files should not be created physically but as stream. This stream will be converted to base64string and saved in database for the use of send mail and Receiver will extract this multiple rar files in one .pdf report?

 or could you able suggest different way?

 

Error While deleting the files after zipping
Debarati Chattopadhyay replied to Peter Bromberg at Friday, October 17, 2008 4:38 PM

Hello Peter

I am using your methods to zip all files in a perticular folder.  The function is doing the required operation, but after zipping the files when I am trying to delete the files its showing me the following error.

"The process cannot access the file because it is being used by another process."

I have closed all the file stream after zipping the file,

Can you suggest me why I am getting this error.

 

Thanks

Debarati

 

You would have to post some sample code.
Peter Bromberg replied to Debarati Chattopadhyay at Friday, October 17, 2008 7:39 PM
All your streams (FileStream and derivatevs) must be closed before you can attempt a delete operation. But without seeing what your code actually looks like, it would be difficult to guess where the problem is.
 

Problem with Zipping files
Debarati Chattopadhyay replied to Peter Bromberg at Tuesday, October 21, 2008 3:34 PM

Hello Peter

Thanks for your response. I am using the same code as provided by you. I am furnishing the code below.

public static void ZipFiles(string inputFolderPath, string outputPathAndFile, string password)

{

FileStream ostream = null;

ZipOutputStream oZipStream = null;

ZipEntry oZipEntry = null;

byte[] obuffer;

//If the Zip stream already exists then

//My Input folder is c:\Test which contains 7 .txt files.

string outPath = inputFolderPath + @"\" + outputPathAndFile;

try

{

if (File.Exists(outPath))

{

File.Delete(outPath);

}

ArrayList ar = GenerateFileList(inputFolderPath); // generate file list

//remove the log file from the list.

int TrimLength = (Directory.GetParent(inputFolderPath)).ToString().Length;

// find number of chars to remove // from orginal file path

TrimLength += 1; 

oZipStream = new ZipOutputStream(File.Create(outPath)); // create zip stream

if (password != null && password != String.Empty)

oZipStream.Password = password;

oZipStream.SetLevel(9); // maximum compression

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);

}

}

}

catch (Exception ex)

{

string strmg = ex.Message.ToString();

}

finally

{

ostream.Flush();

oZipStream.Finish();

ostream.Close();

ostream.Dispose();

ostream = null;

oZipStream.Close();

oZipStream.Dispose();

oZipStream = null;

oZipEntry = null;

obuffer = null;

//Delete the directory and all the files inside it.

Directory.Delete(inputFolderPath,true);

}

}

I have also written a function which will delete all the files on the folder and i have called that function after ziping the file( In that case i am commenting the Directory.Delete line in Zip function.)

Can you please suggest me why I am getting the error.

Thanks

Debarati

 

 

 

i'm geting a compilation error
hepsy ii replied to Peter Bromberg at Wednesday, June 17, 2009 4:27 AM

Compilation Error

BC30002: Type 'ZipInputStream' is not defined

Namespace or type specified in the Imports 'ICSharpCode.SharpZipLib.Zip' doesn't contain any public member or cannot be found

can u please help me

it worked fine on my local system, but it gives error online
i uploaded the dll in the bin folder online

thank u

 

You need to add a ostream.Close(); to stop a handle leak
Colin Critch replied to Peter Bromberg at Friday, June 19, 2009 6:08 AM
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);

        ostream.Close(); // stop read handle leak

  }

Thanks for the Code

Cheers

Colin

 

error zipping files
Cristi Calinescu replied to Peter Bromberg at Wednesday, September 16, 2009 3:20 AM

hi,

   i'm using the exact code given above.

 i'm also using

path = "c:\\test\\";

IcsZipper.ZipUtil.ZipFiles(path, "c:\\", "");

but i get the debug error: The given path's format is not supported.

at line

ZipOutputStream oZipStream = new ZipOutputStream(File.Create(outPath));

the outpath is "c:\\test\\\\c:\\"

 

Please advice:)

 

Error! Help me please!
Dang Phi Hung replied to Cristi Calinescu at Friday, September 18, 2009 5:39 AM
I have using your application but when I zip with large file ( <500Mb) I have error!
Please help me! Thank
 

  ICSharpCode.SharpZipLib.Zip not working using meory stream
Rajesh Moturu replied to Dang Phi Hung at Monday, November 02, 2009 7:14 AM
 

I am trying to zip and unzip PPTX(2007) with the help of ICSharpCode.SharpZipLib.Zip in Memory stream.

I am trying to updated those xml files (Unzipped PPTX files) with input data,without disturbing the structure of the xml .

Finally I am ziping those xml files and writing to PPTX .

When I tried to open this pptx,throws an error saying Files are corrupted.

 my Question is

Is there any chance of corrupting the xml files while unzip in memory stream.

Plese find the sample code ;

using (ZipOutputStream outputFile = new ZipOutputStream(file))

            {

                using (MemoryStream templateBuffer = new MemoryStream((TemplateResources.OpenXmlPPT)))

                {

                    using (ZipInputStream templateFile = new ZipInputStream(templateBuffer))

                    {

                        ZipEntry entry;

                        while ((entry = templateFile.GetNextEntry()) != null)

                        {

                            ZipEntry newEntry = new ZipEntry(entry.Name);

                            outputFile.PutNextEntry(newEntry);

 

                            if (String.Equals(entry.Name, "ppt/embeddings/Microsoft_Office_Excel_Worksheet2.xlsx", StringComparison.OrdinalIgnoreCase))

                            {

 

                                WriteUnzipExcell(templateFile, outputFile, entry);

 

                             }

                            else if (String.Equals(entry.Name, "ppt/charts/chart2.xml", StringComparison.OrdinalIgnoreCase))

                            {

                                byte[] sharedbuffer = new byte[entry.Size];

                                templateFile.Read(sharedbuffer, 0, (int)entry.Size);

                                XDocument XChartDocument = XDocument.Load(new MemoryStream(sharedbuffer));

                                WriteChartDocument(XChartDocument);

 

                                var streamToWrite = GetStream(XChartDocument);

                                outputFile.Write(streamToWrite, 0, streamToWrite.Length);

 

                            }

                            else

                            {

                                CopyStreamToOutputFile(templateFile, outputFile);

                            }

 

                        }

                    }

                }

            }