Rebex



ZIP Tutorial

Back to tutorial list...

Table of content


# Namespaces and assemblies

To use the features of Rebex ZIP for .NET described here, you have to reference the Rebex.Zip.dll assembly in your project. It contains the ZipArchive and other classes in Rebex.IO.Compression namespace.

In your source files, import the following namespace:

C#

using Rebex.IO.Compression;

VB.NET

Imports Rebex.IO.Compression

 

back to top...


# Simple API - static methods

The ZipArchive class provides a set of static methods. These can be used to achieve simple actions:

Compression

C#

// add content of the local directory C:\Data\  
// to the directory \Data-2010 (within the ZIP archive) 
// (ZIP archive C:\archive.zip doesn't have to exist) 
ZipArchive.Add(@"C:\archive.zip", @"C:\Data\*", @"\Data-2010");

// add all *.TXT files from the local directory C:\Data\  
// to the directory \Data-2010 (within the ZIP file) 
// (ZIP archive C:\archive.zip doesn't have to exist) 
ZipArchive.Add(@"C:\archive.zip", @"C:\Data\*.txt", @"\Data-2010");

// add all *.TXT files from the local directory C:\Data\  
// to the root of the ZIP file overwriting all already existing files 
// (ZIP archive C:\archive.zip doesn't have to exist) 
ZipArchive.Add(
    @"C:\archive.zip",
    @"C:\Data\*.txt",
    @"\",
    ArchiveTraversalMode.NonRecursive,
    ArchiveActionOnExistingFile.OverwriteAll);

VB.NET

' add content of the local directory C:\Data\  
' to the directory \Data-2010 (within the ZIP archive) 
' (ZIP archive C:\archive.zip doesn't have to exist) 
ZipArchive.Add("C:\archive.zip", "C:\Data\*", "\Data-2010")

' add all *.TXT files from the local directory C:\Data\  
' to the directory \Data-2010 (within the Zip file) 
' (ZIP archive C:\archive.zip doesn't have to exist) 
ZipArchive.Add("C:\archive.zip", "C:\Data\*.txt", "\Data-2010")

' add all *.TXT files from the local directory C:\Data\  
' to the root of the Zip file overwriting all already existing files 
' (ZIP archive C:\archive.zip doesn't have to exist) 
ZipArchive.Add( _
    "C:\archive.zip", _
    "C:\Data\*.txt", _
    "/", _
    ArchiveTraversalMode.NonRecursive, _
    ArchiveActionOnExistingFile.OverwriteAll)

Decompression

C#

// extract whole content of the ZIP archive to the existing local directory C:\Data 
ZipArchive.ExtractAll(@"C:\archive.zip", @"C:\Data");

// extract whole content of the directory \Data-2010 (within the ZIP file) 
// to the existing local directory C:\Data 
ZipArchive.Extract(@"C:\archive.zip", @"\Data-2010\*", @"C:\Data");

// extract all *.TXT files from the directory \Data-2010 (within the ZIP file) 
// to the existing local directory C:\Data 
ZipArchive.Extract(@"C:\archive.zip", @"\Data-2010\*.html", @"C:\Data");

VB.NET

' extract whole content of the ZIP archive to the existing local directory C:\Data 
ZipArchive.ExtractAll("C:\archive.zip", "C:\Data")

' extract whole content of the directory \Data-2010 (within the ZIP file) 
' to the existing local directory C:\Data 
ZipArchive.Extract("C:\archive.zip", "\Data-2010\*", "C:\Data")

' extract all *.TXT files from the directory \Data-2010 (within the ZIP file) 
' to the existing local directory C:\Data 
ZipArchive.Extract("C:\archive.zip", "\Data-2010\*.html", "C:\Data")

Deleting

C#

// deletes all *.TXT files from the root of the ZIP archive 
ZipArchive.Delete(@"C:\archive.zip", "*.txt", ArchiveTraversalMode.NonRecursive);

// deletes directory \Data-2009 with all of its content 
ZipArchive.Delete(@"C:\archive.zip", @"\Data-2009", ArchiveTraversalMode.Recursive);

VB.NET

' deletes all *.TXT files from the root of the ZIP archive 
ZipArchive.Delete("C:\archive.zip", "*.txt", ArchiveTraversalMode.NonRecursive)

' deletes directory \Data-2009 with all of its content 
ZipArchive.Delete("C:\archive.zip", "\Data-2009", ArchiveTraversalMode.Recursive)

If you need more features than those offered by the simple static methods (such as retrieving a list of files in a ZIP archive or displaying a progress bar) you will have to open a ZIP archive by creating a new instance of the ZipArchive class.

 

back to top...


# ZIP basics - opening and closing a ZIP archive

To open a ZIP archive, simply create a new instance of of the ZipArchive class. Then use its methods to perform the desired actions.

When you are done with the ZIP archive, call ZipArchive object's Close method to close the underlying file (and save pending changes if required). Alternatively, utilize the using keyword.

Opening a ZIP archive

C#

// open the ZIP archive from an existing file 
ZipArchive zip = new ZipArchive(@"C:\archive.zip", ArchiveOpenMode.Open);

// ... do some work 

// close the archive 
zip.Close(ArchiveSaveAction.Auto);

VB.NET

' open the ZIP archive from an existing file 
Dim zip As New ZipArchive("C:\archive.zip", ArchiveOpenMode.Open)

' ... do some work 

' close the ZIP archive 
zip.Close(ArchiveSaveAction.Auto)

Listing the contents of the ZIP archive

Note the use of using keyword here.

C#

// open the ZIP archive 
using (ZipArchive zip = new ZipArchive(@"C:\archive.zip"))
{
    // get collection of all items in the root of the ZIP archive 
    ZipItemCollection items = zip.GetItems(@"\", ArchiveTraversalMode.Recursive);

    // sort the collection by name (directories first) 
    items.Sort();

    // display info about each item 
    foreach (ZipItem item in items)
    {
        if (item.IsDirectory)
            Console.WriteLine("D {0} [{1}]", item.Name, item.LastWriteTime);
        else 
            Console.WriteLine(
                "f {0} {1}B [{2}]", item.Name, item.Length, item.LastWriteTime);
    }
}

VB.NET

' open the ZIP archive 
Using zip As New ZipArchive("C:\archive.zip")
    ' get collection of all items in the root of the ZIP archive 
    Dim items = zip.GetItems("/", ArchiveTraversalMode.Recursive)

    ' sort the collection by name (directories first) 
    items.Sort()

    ' display info about each item 
    For Each item As ZipItem In items
        If item.IsDirectory Then 
            Console.WriteLine("D {0} [{1}]", item.Name, item.LastWriteTime)
        Else 
            Console.WriteLine( _
                "f {0} {1}B [{2}]", item.Name, item.Length, item.LastWriteTime)
        End If 
    Next item
End Using 

 

back to top...


# Adding files (compressing)

To add files into the ZIP archive, use Add or AddFile methods.

The AddFile method only adds a single file. This makes it possible to specify a different file name for it. To use the original name, just specify the target directory path with an ending slash instead.

C#

// add 'C:\Data\file.txt' file to the (root of the) ZIP archive 
zip.AddFile(@"C:\Data\file.txt");

// add local file to the archive directory \Data-2010  
// and name the added file "file-01.txt" 
zip.AddFile(@"C:\Data\file.txt", @"\Data-2010\file-01.txt");

// add local file to the \Data-2010\ archive directory 
// (the ending slash in the archive path indicates that you 
// actually mean a directory instead of an extension-less file name) 
zip.AddFile(@"C:\Data\file.txt", @"\Data-2010\");

VB.NET

' add 'C:\Data\file.txt' file to the (root of the) ZIP archive 
zip.AddFile("C:\Data\file.txt")

' add local file to the archive directory \Data-2010  
' and name the added file "file-01.txt" 
zip.AddFile("C:\Data\file.txt", "\Data-2010\file-01.txt")

' add local file to the \Data-2010\ archive directory 
' (the ending slash in the archive path indicates that you 
' actually mean a directory instead of an extension-less file name) 
zip.AddFile("C:\Data\file.txt", "\Data-2010\")

The Add method adds multiple files or directories in a single call. The first argument specifies a file, a directory or a group of files or directories (see path/mask) to add. The second argument is the target directory path (in the ZIP archive). Optional arguments specify various compression options like traversal mode or action on existing files.

C#

// add all; *.txt files from 'C:\Data' 
// to the (root of the) ZIP archive 
zip.Add(@"C:\Data\*.txt");

// add all *.txt files from 'C:\Data' 
// to the '\Data-2010' directory in the ZIP archive 
zip.Add(@"C:\Data\*.txt", @"\Data-2010");

// add the whole content of 'C:\Data' 
// to the '\Data-2010' directory in the ZIP archive 
// (overwrite all already-existing files) 
zip.Add(
    @"C:\Data\*",
    @"\Data-2010",
    ArchiveTraversalMode.Recursive,
    ArchiveActionOnExistingFile.OverwriteAll);

VB.NET

' add all; *.txt files from 'C:\Data' 
' to the (root of the) ZIP archive 
zip.Add("C:\Data\*.txt")

' add all *.txt files from 'C:\Data' 
' to the '\Data-2010' directory in the ZIP archive 
zip.Add("C:\Data\*.txt", "\Data-2010")

' add the whole content of 'C:\Data' 
' to the '\Data-2010' directory in the ZIP archive 
' (overwrite all already-existing files) 
zip.Add( _
    "C:\Data\*", _
    "\Data-2010", _
    ArchiveTraversalMode.Recursive, _
    ArchiveActionOnExistingFile.OverwriteAll)

 

back to top...


# Extracting files (decompressing)

To extract data from a ZIP archive, use Extract, ExtractAll or ExtractFile methods.

The ExtractFile method only extracts a single file. This makes it possible to specify a different file name for it. To use the original name, just specify the target directory path with an ending slash instead.

C#

// extract '\Data-2010\file.txt' file to 'C:\Data\file-01.txt' file 
zip.ExtractFile(@"\Data-2010\file.txt", @"C:\Data\file-01.txt");

// extract '\Data-2010\file.txt' file to 'C:\Data' directory 
// (the ending slash in the archive path indicates that you 
// actually mean a directory instead of an extension-less file name) 
zip.ExtractFile(@"\Data-2010\file.txt", @"C:\Data\");

VB.NET

' extract '\Data-2010\file.txt' file to 'C:\Data\file-01.txt' file 
zip.ExtractFile("\Data-2010\file.txt", "C:\Data\file-01.txt")

' extract '\Data-2010\file.txt' file to 'C:\Data' directory 
' (the ending slash in the archive path indicates that you 
' actually mean a directory instead of an extension-less file name) 
zip.ExtractFile("\Data-2010\file.txt", "C:\Data\")

The Extract method extracts multiple files or directories in a single call. The first argument specifies a file, a directory or a group of files and directories (see path/mask) to extract. The second argument is the target directory path (in the local filesystem). Optional arguments specify various compression options like traversal mode or action on existing files.

C#

// extract whole ZIP archive to 'C:\Data' directory 
zip.ExtractAll(@"C:\Data");

// extract all *.txt files from '\Data-2010' archive directory 
// to 'C:\Data' directory 
zip.Extract(@"\Data-2010\*.txt", @"C:\Data");

// extract whole content of '\Data-2010' archive directory  
// to 'C:\Data' directory and overwrite all already-existing files 
zip.Extract(
    @"\Data-2010\*",
    @"C:\Data",
    ArchiveTraversalMode.Recursive,
    ArchiveActionOnExistingFile.OverwriteAll);

VB.NET

' extract whole ZIP archive to 'C:\Data' directory 
zip.ExtractAll("C:\Data")

' extract all *.txt files from '\Data-2010' archive directory 
' to 'C:\Data' directory 
zip.Extract("\Data-2010\*.txt", "C:\Data")

' extract whole content of '\Data-2010' archive directory  
' to 'C:\Data' directory and overwrite all already-existing files 
zip.Extract( _
    "\Data-2010\*", _
    "C:\Data", _
    ArchiveTraversalMode.Recursive, _
    ArchiveActionOnExistingFile.OverwriteAll)

The ExtractAll method is a shortcut for extracting the whole content of the ZIP archive to the specified directory.

 

back to top...


# Traversal modes

Traversal mode is an optional argument for Add, Extract and Delete methods. It specifies whether to include the content of subdirectories in the requested operation, and how to traverse them:

ArchiveTraversalMode

  • ArchiveTraversalMode.NonRecursive - Only compresses files and directories matching the specified path/mask. The content of matched directories is not compressed.
  • ArchiveTraversalMode.Recursive - Recursive mode. Processes all files and subdirectories matching the specified path/mask. If the source path is a masked path, files/directories in the first level are matched and if their name matches the specified mask, their whole content is compressed. (For example, source path "C:\Data\text*" compresses all files and directories whose name starts with "text" - any files and subdirectories in the matched directories are also compressed, regardless of their names).
  • ArchiveTraversalMode.DeepMatch - Recursive xcopy-like mode. This is similar to Recursive mode, but the mask is applied to files on all levels and all subdirectories are included in the search. (DeepMatch mode can create a lot of empty directories if a wide directory hierarchy is specified but only contains few matching files.)

 

back to top...


# Deleting files and directories within the archive

To delete a file or a directory in the ZIP archive, use Delete method. Optionally, specify a traversal mode (useful when deleting a whole directory tree).

Another optional argument is a save action - this makes it possible to either rearrange (shrink) the ZIP file to remove the unused space left by the deleted files. By default, Delete method does rearrange the ZIP file if needed (ArchiveSaveAction.Auto). An alternative is to specify ArchiveSaveAction.None to skip rearranging (shrinking) and perform this operation later by explicitly calling Save(ArchiveSaveAction.Shrink) method later or Close(ArchiveSaveAction.Shrink) method when closing the archive.

C#

// delete 'file.txt' 
zip.Delete(@"\file.txt");

// delete whole '\Data-2009' directory with all subfiles and subdirectories 
zip.Delete(@"\Data-2009", ArchiveTraversalMode.Recursive);

// delete several files without shrinking (to save time) 
zip.Delete(@"\file1.txt", ArchiveSaveAction.None);
zip.Delete(@"\file2.txt", ArchiveSaveAction.None);
zip.Delete(@"\file3.txt", ArchiveSaveAction.None);
// now shrink the archive (remove any unused space) 
zip.Save(ArchiveSaveAction.Shrink);

// delete whole '\Data-2009' directory with all its files and subdirectories, 
// save any changes and shrink the archive - all in one call 
zip.Delete(@"\Data-2009", ArchiveTraversalMode.Recursive, ArchiveSaveAction.Shrink);

VB.NET

' delete 'file.txt' 
zip.Delete("\file.txt")

' delete whole '\Data-2009' directory with all subfiles and subdirectories 
zip.Delete("\Data-2009", ArchiveTraversalMode.Recursive)

' delete several files without shrinking (to save time) 
zip.Delete("\file1.txt", ArchiveSaveAction.None)
zip.Delete("\file2.txt", ArchiveSaveAction.None)
zip.Delete("\file3.txt", ArchiveSaveAction.None)
' now shrink the archive (remove any unused space) 
zip.Save(ArchiveSaveAction.Shrink)

' delete whole '\Data-2009' directory with all its files and subdirectories, 
' save any changes and shrink the archive - all in one call 
zip.Delete("\Data-2009", ArchiveTraversalMode.Recursive, ArchiveSaveAction.Shrink)

 

back to top...


# Moving (renaming) files withing the archive

To move and rename files or directories in a ZIP archive, use ZipArchive object's Move method (rename or move) or ZipItem object's Rename method (rename only).

C#

// get the item object for '\dir\file.txt' 
ZipItem item = zip.GetItem(@"\dir\file.txt");
// rename the item (the new path will be '\dir\renamed.txt') 
item.Rename("renamed.txt");

// move the '\dir\file.txt' file to '\moved' directory 
zip.Move(@"\dir\file.txt", @"\moved\file.txt");

// move the "\dir\file.txt" file to '\moved' directory 
// and rename it to 'renamed.txt" 
zip.Move(@"\dir\file.txt", @"\moved\renamed.txt");

VB.NET

' get the item object for '\dir\file.txt' 
Dim item As ZipItem = zip.GetItem("\dir\file.txt")
' rename the file (the new path will be '\dir\renamed.txt') 
item.Rename("renamed.txt")

' move the '\dir\file.txt' file to '\moved' directory 
zip.Move("\dir\file.txt", "\moved\file.txt")

' move the "\dir\file.txt" file to '\moved' directory 
' and rename it to 'renamed.txt" 
zip.Move("\dir\file.txt", "\moved\renamed.txt")

 

back to top...


# Listing ZIP archive contents

Each file and directory within a ZIP archive (ZipArchive class) is represented by a ZipItem object that holds information such as name, compressed/uncompressed length, last modification date, comment, etc. ZipItem can be retrieved by 2 methods.

  • GetItem method or ZipArchive indexer - returns a ZipItem object that represents the specified file or directory (or null/Nothing if it doesn't exist).
  • GetItems method - returns a collection of ZipItem objects matching the specified arguments. (GetItems returns a list of files that would be extracted if the Extract method with identical arguments was called.)

C#

// get information about the '\Data-2010' directory 
ZipItem info1 = zip.GetItem(@"\Data-2010");

// equivalent to the previous call (GetItem method) 
ZipItem info2 = zip[@"\Data-2010"];

// get all items (files and directories) in the '\Data-2010' directory 
ZipItemCollection items = zip.GetItems(@"\Data-2010", ArchiveTraversalMode.NonRecursive);

// get all items (files and directories) from the 'Data-2010' directory  
// including all subdirectories 
ZipItemCollection allItems = zip.GetItems(
    @"\Data-2010",
    ArchiveTraversalMode.Recursive);

// get all directories whose name starts with 'Data' 
ZipItemCollection dataDirectories = zip.GetItems(
    @"\Data*",
    ArchiveTraversalMode.NonRecursive,
    ArchiveItemTypes.Directories);

// get whole content of all directories whose name starts with 'Data' 
ZipItemCollection dataContent = zip.GetItems(
    @"\Data*",
    ArchiveTraversalMode.Recursive,
    ArchiveItemTypes.All);

// get all .txt files in the archive 
ZipItemCollection txtFiles = zip.GetItems(
    "*.txt",
    ArchiveTraversalMode.DeepMatch,
    ArchiveItemTypes.Files);

VB.NET

' get information about the '\Data-2010' directory 
Dim info1 = zip.GetItem("\Data-2010")

' equivalent to the previous call (GetItem method) 
Dim info2 = zip("\Data-2010")

' get all items (files and directories) in the '\Data-2010' directory 
Dim items = zip.GetItems("\Data-2010", ArchiveTraversalMode.NonRecursive)

' get all items (files and directories) from the '\Data-2010' directory  
' including all subdirectories 
Dim allItems As ZipItemCollection = zip.GetItems( _
    "\Data-2010", _
    ArchiveTraversalMode.Recursive)

' get all directories whose name starts with 'Data' 
Dim dataDirectories As ZipItemCollection = zip.GetItems( _
    "\Data*", _
    ArchiveTraversalMode.NonRecursive, _
    ArchiveItemTypes.Directories)

' get whole content of all directories whose name starts with 'Data' 
Dim dataContent As ZipItemCollection = zip.GetItems( _
    "\Data*", _
    ArchiveTraversalMode.Recursive, _
    ArchiveItemTypes.Directories)

' get all .txt files in the archive 
Dim txtFiles As ZipItemCollection = zip.GetItems( _
    "*.txt", _
    ArchiveTraversalMode.Recursive, _
    ArchiveItemTypes.Files)

 

back to top...


# Protecting ZIP with password

To encrypt files, simply set the Password property of the ZipArchive class first. From the moment you set the Password newly added files are encrypted until you unset the Password. Unset means assign a null reference (Nothing in Visual Basic) to the Password property. Note that setting the Password property to an empty string causes the files to be encrypted with the empty password.

To use other than default encryption algorithm, use the EncryptionAlgorithm property of the ZipArchive class. Please note that we also support Zip 2.0 (traditional PKWARE encryption) to enable compatibility with old legacy applications, but this algorithm is considered weak by today's standards.

C#

// create new ZIP archive 
using (ZipArchive zip = new ZipArchive(@"C:\archive.zip", ArchiveOpenMode.Create))
{
    // set the Password first 
    zip.Password = "PASSword#123";

    // optionally change the default Encryption algorithm 
    zip.EncryptionAlgorithm = EncryptionAlgorithm.Aes128;

    // now add files 
    zip.Add(@"C:\Data");
}

VB.NET

' create new ZIP archive 
Using zip As New ZipArchive("C:\archive.zip", ArchiveOpenMode.Create)
    ' set the Password first 
    zip.Password = "PASSword#123"

    ' optionally change the default Encryption algorithm 
    zip.EncryptionAlgorithm = EncryptionAlgorithm.Aes128

    ' now add files 
    zip.Add("C:\Data")
End Using 

Decryption process is very similar, but you can choose from two ways. Either set the Password property of the ZipArchive class or register the PasswordRequired event. The event is fired when you are trying to extract encrypted file, but you didn't specify a password or when the specified password is invalid.

C#

// open a ZIP archive 
using (ZipArchive zip = new ZipArchive(@"C:\archive.zip", ArchiveOpenMode.Open))
{
    // set the Password first 
    zip.Password = "PASSword#123";

    // extract whole ZIP content 
    zip.ExtractAll(@"C:\Data");
}

VB.NET

' open a ZIP archive 
Using zip As New ZipArchive("C:\archive.zip", ArchiveOpenMode.Open)
    ' set the Password first 
    zip.Password = "PASSword#123"

    ' extract whole ZIP content 
    zip.ExtractAll("C:\Data")
End Using 

Real scenario decryption process using PasswordRequired event is shown in the ZIP Extractor sample.

C#

// open a ZIP archive 
using (ZipArchive zip = new ZipArchive(@"C:\archive.zip", ArchiveOpenMode.Open))
{
    // set the PasswordRequired event first 
    zip.PasswordRequired += 
        new EventHandler<ZipPasswordRequiredEventArgs>(zip_PasswordRequired);

    // extract whole ZIP content 
    zip.ExtractAll(@"C:\Data");
}

// ... 
// handler for the PasswordRequired event 
void zip_PasswordRequired(object sender, ZipPasswordRequiredEventArgs e)
{
    // get the password from user 
    string password = GetUserPassword();

    // set the Password or Cancel whole operation 
    if (password == null)
        e.Action = ArchivePasswordActions.Cancel;
    else 
        e.Password = password;
}

VB.NET

' open a ZIP archive 
Using zip As New ZipArchive("C:\archive.zip", ArchiveOpenMode.Open)
    ' set the PasswordRequired event first 
    AddHandler zip.PasswordRequired, AddressOf zip_PasswordRequired

    ' extract whole ZIP content 
    zip.ExtractAll("C:\Data")
End Using 

' ... 
' handler for the PasswordRequired event 
Public Sub zip_PasswordRequired( _
    ByVal sender As Object, _
    ByVal e As ZipPasswordRequiredEventArgs)

    ' get the password from user 
    Dim password = GetUserPassword()

    ' set the Password or Cancel whole operation 
    If password Is Nothing Then 
        e.Action = ArchivePasswordActions.Cancel
    Else 
        e.Password = password
    End If 
End Sub 

 

back to top...


# Progress info and progress event

To get informed about the progress of the current compress/decompress operations, just register the ProgressChanged event.

When using multi-file operations like Add, Extract or ExtractAll methods, the ProgressChanged event handler will receive useful information: currently processed file, its length, total progress, number of bytes processed, etc.

When only processing a single file using AddFile or ExtractFile method, the ProgressChanged event handler will still receive a subset of the above-mentioned information (like CurrentFileProcessedPercentage).

C#

// register the Progress event 
zip.ProgressChanged +=
    new EventHandler<ZipProgressChangedEventArgs>(zip_ProgressChanged);

// extract all files, this will fire the Progress event 
zip.ExtractAll(@"C:\Data");

// ... 
// handler for the Progress event 
void zip_ProgressChanged(object sender, ZipProgressChangedEventArgs e)
{
    switch (e.OperationStep)
    {
        // display info about currently compressing/extracting file 
        case ArchiveOperationStep.FileProcessing:
            if (e.Operation == ArchiveOperation.Add)
                Console.WriteLine(
                    "Compressing file '{0}' to '{1}' {2}B [{3}/{4}] ...",
                    e.ExternalItemPath,
                    e.ArchiveItemPath,
                    e.CurrentFileLength,
                    e.FilesProcessed + 1,
                    e.FilesTotal);
            else 
                Console.WriteLine(
                    "Extracting file '{0}' to '{1}' {2}B [{3}/{4}]...",
                    e.ArchiveItemPath,
                    e.ExternalItemPath,
                    e.CurrentFileLength,
                    e.FilesProcessed + 1,
                    e.FilesTotal);
            break;

        // display progress of curently compressing/extracting file  
        // and progress of the whole operation 
        case ArchiveOperationStep.FileDataBlockProcessed:
            Console.WriteLine(
                "{0} [{2}% / {3}%]",
                Path.GetFileName(e.ExternalItemPath),
                e.CurrentFileProgressPercentage,
                e.ProgressPercentage);
            break;
    }
}

VB.NET

' register the Progress event 
AddHandler zip.ProgressChanged, AddressOf zip_ProgressChanged

' extract all files, this will fire the Progress event 
zip.ExtractAll("C:\Data")

' ... 
' handler for the Progress event 
Public Sub zip_ProgressChanged( _
    ByVal sender As Object, _
    ByVal e As ZipProgressChangedEventArgs)

    Select Case e.OperationStep
        Case ArchiveOperationStep.FileProcessing
            ' display info about currently compressing/extracting file 

            If e.Operation = ArchiveOperation.Add Then 
                Console.WriteLine( _
                "Compressing file '{0}' to '{1}' {2}B [{3}/{4}] ...", _
                e.ExternalItemPath, _
                e.ArchiveItemPath, _
                e.CurrentFileLength, _
                e.FilesProcessed + 1, _
                e.FilesTotal)
            Else 
                Console.WriteLine( _
                "Extracting file '{0}' to '{1}' {2}B [{3}/{4}]...", _
                e.ArchiveItemPath, _
                e.ExternalItemPath, _
                e.CurrentFileLength, _
                e.FilesProcessed + 1, _
                e.FilesTotal)
            End If 

        Case ArchiveOperationStep.FileDataBlockProcessed
            ' display progress of curently compressing/extracting file  
            ' and progress of the whole operation 

            Console.WriteLine( _
                "{0} [{2}% / {3}%]", _
               Path.GetFileName(e.ExternalItemPath), _
               e.CurrentFileProgressPercentage, _
               e.ProgressPercentage)
    End Select 
End Sub 

 

back to top...


# Handling multi-file operation problems

With multi-file operations, things can occasionally go wrong due to unforeseen problems. To be informed about such problems, just register the ProblemDetected event. When things go wrong (e.g. a file we are trying to extract already exists in the target folder), the the ProblemDetected event is raised and it can be used to specify the desired action to take.

The type of the problem is determined using the event-argument's ProblemType property. This describes what is going on. Exception property contains further information - it's actually an exception that would be thrown unless a different action is choosen. Use IsActionPossible method (or PossibleActions flag property) to determine which actions are possible, and specify the desired action using the Action property.

C#

// register the ProblemDetected event 
zip.ProblemDetected +=
    new EventHandler<ZipProblemDetectedEventArgs>(zip_ProblemDetected);

// extract all files, this will fire the ProblemDetected event if any problem occurs 
zip.ExtractAll(@"C:\Data");

// ... 
// handler for the ProblemDetected event 
void zip_ProblemDetected(object sender, ZipProblemDetectedEventArgs e)
{
    switch (e.ProblemType)
    {
        // overwrite already existing files and inform the user 
        case ArchiveProblemType.FileExists:
            if (e.IsActionPossible(ArchiveProblemActions.Overwrite))
            {
                if (e.Operation == ArchiveOperation.Add)
                    Console.WriteLine(
                        "Overwriting file {0} with {1}...",
                        e.ArchiveItemPath,
                        e.ExternalItemPath);
                else 
                    Console.WriteLine(
                        "Overwriting file {0} with {1}...",
                        e.ExternalItemPath,
                        e.ArchiveItemPath);
                e.Action = ArchiveProblemActions.Overwrite;
            }
            break;

        // if CRC check faild while extracting a file, delete unusable local file, 
        // inform the user and continue in batch processing  
        // by skipping this corrupted file 
        case ArchiveProblemType.CrcCheckFailed:

            Console.WriteLine(
                "CRC check faild. Deleting local file {0}...",
                e.ExternalItemPath);

            File.Delete(e.ExternalItemPath);
            e.Action = ArchiveProblemActions.Skip;
            break;
    }
}

VB.NET

' register the Progress event 
AddHandler zip.ProblemDetected, AddressOf zip_ProblemDetected

' extract all files, this will fire the ProblemDetected event if any problem occurs 
zip.ExtractAll("C:\Data")

' ... 
' handler for the ProblemDetected event 
Public Sub zip_ProblemDetected( _
    ByVal sender As Object, _
    ByVal e As ZipProblemDetectedEventArgs)

    Select Case e.ProblemType
        ' overwrite already existing files and inform the user 
        Case ArchiveProblemType.FileExists
            If e.IsActionPossible(ArchiveProblemActions.Overwrite) Then 
                If e.Operation = ArchiveOperation.Add Then 
                    Console.WriteLine( _
                        "Overwriting file {0} with {1}...", _
                        e.ArchiveItemPath, _
                        e.ExternalItemPath)
                Else 
                    Console.WriteLine( _
                        "Overwriting file {0} with {1}...", _
                        e.ExternalItemPath, _
                        e.ArchiveItemPath)
                End If 
                e.Action = ArchiveProblemActions.Overwrite
            End If 

            ' if CRC check failed while extracting a file, delete unusable local file, 
            ' inform the user and continue in batch processing  
            ' by skipping this corrupted file 
        Case ArchiveProblemType.CrcCheckFailed

            Console.WriteLine( _
                "CRC check faild. Deleting local file {0}...", _
                e.ExternalItemPath)

            File.Delete(e.ExternalItemPath)
            e.Action = ArchiveProblemActions.Skip
    End Select 
End Sub 

 

back to top...


# Compression level

When compressing data, you can choose between compression speed and quality using the ZipArchive object's CompressionLevel property. Levels from 0 to 9 are supported:

  • 0 = No compression, but very fast.
  • 1 = The fastest compression, but the worst compression ratio.
  • 6 = Default compression, a compromise between speed and compression ratio.
  • 9 = Best compression ratio, but the slowest.

C#

// open a ZIP archive 
using (ZipArchive zip = new ZipArchive(@"C:\archive.zip"))
{
    // get files in the 'C:\Data' directory 
    string[] files = Directory.GetFiles(@"C:\Data");

    // choose compression level for each file according to the file type 
    foreach (string file in files)
    {
        switch (Path.GetExtension(file))
        {
            // don't waste time with already-compressed files 
            case ".jpg":
            case ".gif":
            case ".mp3":
                zip.CompressionLevel = 0;
                zip.AddFile(file);
                break;

            // use best compression for all other files 
            default:
                zip.CompressionLevel = 9;
                zip.AddFile(file);
                break;
        }
    }
}

VB.NET

' open a ZIP archive 
Using zip As New ZipArchive("C:\archive.zip")
    ' get files in the 'C:\Data' directory 
    Dim files = Directory.GetFiles("C:\Data")

    ' choose compression level for each file according to the file type 
    For Each File As String In files
        Select Case Path.GetExtension(File)
            ' don't waste time with already-compressed files 
            Case ".jpg", ".gif", ".mp3"
                zip.CompressionLevel = 0
                zip.AddFile(File)

                ' use best compression for all other files 
            Case Else 
                zip.CompressionLevel = 9
                zip.AddFile(File)
        End Select 
    Next File
End Using 

 

back to top...


# Advanced optimisation hints

The ZipArchive class exposes the ArchiveSaveMode property which is set to ArchiveSaveMode.Immediate by default. This value causes all changes made to the ZIP archive to be saved to the underlying stream immediately. Although this makes the ZipArchive class very easy to use, it can cause a noticeable slow-down when performing a lot of "single" operations. For example, updating the LastWriteTime property of 1000s of files will cause the full ZIP archive central-directory-structure to be saved 1000s of times again and again as well.

To avoid this, switch the ZipArchive object to ArchiveSaveMode.Delayed mode, perform the "single" operations and explicitly call the Save method to save all changes once.

In a similar fashion, Delete method called with ArchiveSaveAction.Auto argument rearranges (shrinks) the ZIP archive in ArchiveSaveMode.Immediate mode. If you need to perform many single Delete operations, switching to ArchiveSaveMode.Delayed mode temporarily might result in a great speed boost.

C#

// open a ZIP archive 
using (ZipArchive zip = new ZipArchive(@"C:\archive.zip"))
{
    // turn off "immediately saving mode" 
    zip.SaveMode = ArchiveSaveMode.Delayed;

    // get files in the 'C:\Data' directory 
    string[] files = Directory.GetFiles(@"C:\Data");

    foreach (string file in files)
    {
        string filename = Path.GetFileName(file);
        zip.AddFile(file, filename);

        // set comment and last write time for the newly-added file 
        zip[filename].Comment = "Comment for file " + filename;
        zip[filename].LastWriteTime = DateTime.Now;
    }

    // save all changes (comments and write times) made earlier 
    // (this needs to be called before turning on auto-save again) 
    zip.Save();

    // turn on 'auto-save' mode  
    zip.SaveMode = ArchiveSaveMode.Immediate;

    // ... do some work with ZIP archive in "immediately saving mode" 
}

VB.NET

' open a ZIP archive 
Using zip As New ZipArchive("C:\archive.zip")
    ' turn off "immediately saving mode" 
    zip.SaveMode = ArchiveSaveMode.Delayed

    ' get files in the 'C:\Data' directory 
    Dim files = Directory.GetFiles("C:\Data")

    For Each file As String In files
        Dim filename As String = Path.GetFileName(file)
        zip.AddFile(file, filename)

        ' set comment and last write time for the newly-added file 
        zip(filename).Comment = "Comment for file " + filename
        zip(filename).LastWriteTime = DateTime.Now
    Next file

    ' save all changes (comments and write times) made earlier 
    ' (this needs to be called before turning on auto-save again) 
    zip.Save()

    'turn on 'auto-save' mode 
    zip.SaveMode = ArchiveSaveMode.Immediate

    ' ... do some work with ZIP archive in "immediately saving mode" 
End Using 

 

back to top...


# Used expressions

  • Mask, masked path or path/mask is a path which contains wildcards ('*' or '?'). The wildcards are only allowed at the last level of the path ("C:\Data\*.txt" is a valid path mask, "C:\Data\*\bin" is not).
  • Multi-file operations are methods which process (compress, decompress or delete) more files in a single call.

 

back to top...


Back to tutorial list...