Rebex


ZIP Tutorial

Applies to: Rebex Total Pack, Rebex ZIP

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 and Rebex.Common.dll assemblies 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",
    @"\",
    TraversalMode.NonRecursive,
    TransferMethod.Copy,
    ActionOnExistingFiles.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", _
 "/", _
 TraversalMode.NonRecursive, _
 TransferMethod.Copy, _
 ActionOnExistingFiles.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", TraversalMode.NonRecursive);

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

VB.NET

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

' deletes directory \Data-2009 with all of its content
ZipArchive.Delete("C:\archive.zip", "\Data-2009", TraversalMode.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(@"\", TraversalMode.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("/", TraversalMode.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
// if the file already exists there and is older, overwrite it
// (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\", ActionOnExistingFiles.OverwriteOlder);

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
' if the file already exists there and is older, overwrite it
' (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\", ActionOnExistingFiles.OverwriteOlder)

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",
    TraversalMode.Recursive,
    TransferMethod.Copy,
    ActionOnExistingFiles.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", _
  TraversalMode.Recursive, _
  TransferMethod.Copy, _
  ActionOnExistingFiles.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
// if the file already exists there, the file will be extracted to a renamed copy
// (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\", ActionOnExistingFiles.Rename);

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
' if the file already exists there, the file will be extracted to a renamed copy
' (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\", ActionOnExistingFiles.Rename)

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",
    TraversalMode.Recursive,
    TransferMethod.Copy,
    ActionOnExistingFiles.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", _
  TraversalMode.Recursive, _
  TransferMethod.Copy, _
  ActionOnExistingFiles.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 single file named 'file.txt'
zip.DeleteFile(@"\file.txt");

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

// delete several files and directories without shrinking (to save time)
zip.DeleteFile(@"\file.txt", ArchiveSaveAction.None);
zip.Delete(@"\*.jpg", TraversalMode.MatchFilesShallow, ArchiveSaveAction.None);
zip.Delete(@"\Data-2008", TraversalMode.Recursive, 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", TraversalMode.Recursive, ArchiveSaveAction.Shrink);

VB.NET

' delete single file named 'file.txt'
zip.DeleteFile("\file.txt")

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

' delete several files without shrinking (to save time)
zip.DeleteFile("\file.txt", ArchiveSaveAction.None)
zip.Delete("\*.jpg", TraversalMode.MatchFilesShallow, ArchiveSaveAction.None)
zip.Delete("\Data-2008", TraversalMode.Recursive, 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", TraversalMode.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\*", TraversalMode.NonRecursive);

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

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

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

// get all .txt files in the archive
ZipItemCollection txtFiles = zip.GetItems(
    "*.txt",
    TraversalMode.MatchFilesDeep,
    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\*", TraversalMode.NonRecursive)

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

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

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

' get all .txt files in the archive
Dim txtFiles As ZipItemCollection = zip.GetItems( _
 "*.txt", _
 TraversalMode.MatchFilesDeep, _
 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...