Table of Contents

Class ZipFile

Namespace
Ionic.Zip
Assembly
SunamoDotNetZip.dll

The ZipFile type represents a zip archive file.

[Guid("ebc25cf6-9120-4283-b972-0e5520d00005")]
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDispatch)]
public class ZipFile : IEnumerable<ZipEntry>, IEnumerable, IDisposable
Inheritance
ZipFile
Implements
Inherited Members
Extension Methods

Remarks

This is the main type in the DotNetZip class library. This class reads and writes zip files, as defined in the specification for zip files described by PKWare. The compression for this implementation is provided by a managed-code version of Zlib, included with DotNetZip in the classes in the Ionic.Zlib namespace.

This class provides a general purpose zip file capability. Use it to read, create, or update zip files. When you want to create zip files using a Stream type to write the zip file, you may want to consider the ZipOutputStream class.

Both the ZipOutputStream class and the ZipFile class can be used to create zip files. Both of them support many of the common zip features, including Unicode, different compression methods and levels, and ZIP64. They provide very similar performance when creating zip files.

The ZipFile class is generally easier to use than ZipOutputStream and should be considered a higher-level interface. For example, when creating a zip file via calls to the PutNextEntry() and Write() methods on the ZipOutputStream class, the caller is responsible for opening the file, reading the bytes from the file, writing those bytes into the ZipOutputStream, setting the attributes on the ZipEntry, and setting the created, last modified, and last accessed timestamps on the zip entry. All of these things are done automatically by a call to ZipFile.AddFile(). For this reason, the ZipOutputStream is generally recommended for use only when your application emits arbitrary data, not necessarily data from a filesystem file, directly into a zip file, and does so using a Stream metaphor.

Aside from the differences in programming model, there are other differences in capability between the two classes.

  • ZipFile can be used to read and extract zip files, in addition to creating zip files. ZipOutputStream cannot read zip files. If you want to use a stream to read zip files, check out the ZipInputStream class.
  • ZipOutputStream does not support the creation of segmented or spanned zip files.
  • ZipOutputStream cannot produce a self-extracting archive.

Be aware that the ZipFile class implements the IDisposable interface. In order for ZipFile to produce a valid zip file, you use use it within a using clause (Using in VB), or call the Dispose() method explicitly. See the examples for how to employ a using clause.

Constructors

ZipFile()

Create a zip file, without specifying a target filename or stream to save to.

public ZipFile()

Examples

This example creates a Zip archive called Backup.zip, containing all the files in the directory DirectoryToZip. Files within subdirectories are not zipped up.

using (ZipFile zip = new ZipFile())
{
  // Store all files found in the top level directory, into the zip archive.
  // note: this code does not recurse subdirectories!
  String[] filenames = System.IO.Directory.GetFiles(DirectoryToZip);
  zip.AddFiles(filenames, "files");
  zip.Save("Backup.zip");
}
Using zip As New ZipFile
    ' Store all files found in the top level directory, into the zip archive.
    ' note: this code does not recurse subdirectories!
    Dim filenames As String() = System.IO.Directory.GetFiles(DirectoryToZip)
    zip.AddFiles(filenames, "files")
    zip.Save("Backup.zip")
End Using

Remarks

See the documentation on the ZipFile constructor that accepts a single string argument for basic information on all the ZipFile constructors.

After instantiating with this constructor and adding entries to the archive, the application should call Save(string) or Save(Stream) to save to a file or a stream, respectively. The application can also set the Name property and then call the no-argument Save() method. (This is the preferred approach for applications that use the library through COM interop.) If you call the no-argument Save() method without having set the Name of the ZipFile, either through the parameterized constructor or through the explicit property , the Save() will throw, because there is no place to save the file.

Instances of the ZipFile class are not multi-thread safe. You may have multiple threads that each use a distinct ZipFile instance, or you can synchronize multi-thread access to a single instance.

ZipFile(string)

Creates a new ZipFile instance, using the specified filename.

public ZipFile(string fileName)

Parameters

fileName string

The filename to use for the new zip archive.

Examples

This example shows how to create a zipfile, and add a few files into it.

String ZipFileToCreate = "archive1.zip";
String DirectoryToZip  = "c:\\reports";
using (ZipFile zip = new ZipFile())
{
  // Store all files found in the top level directory, into the zip archive.
  String[] filenames = System.IO.Directory.GetFiles(DirectoryToZip);
  zip.AddFiles(filenames, "files");
  zip.Save(ZipFileToCreate);
}
Dim ZipFileToCreate As String = "archive1.zip"
Dim DirectoryToZip As String = "c:\reports"
Using zip As ZipFile = New ZipFile()
    Dim filenames As String() = System.IO.Directory.GetFiles(DirectoryToZip)
    zip.AddFiles(filenames, "files")
    zip.Save(ZipFileToCreate)
End Using

Remarks

Applications can use this constructor to create a new ZipFile for writing, or to slurp in an existing zip archive for read and update purposes.

To create a new zip archive, an application can call this constructor, passing the name of a file that does not exist. The name may be a fully qualified path. Then the application can add directories or files to the ZipFile via AddDirectory(), AddFile(), AddItem() and then write the zip archive to the disk by calling Save(). The zip file is not actually opened and written to the disk until the application calls ZipFile.Save(). At that point the new zip file with the given name is created.

If you won't know the name of the Zipfile until the time you call ZipFile.Save(), or if you plan to save to a stream (which has no name), then you should use the no-argument constructor.

The application can also call this constructor to read an existing zip archive. passing the name of a valid zip file that does exist. But, it's better form to use the static Read(string) method, passing the name of the zip file, because using ZipFile.Read() in your code communicates very clearly what you are doing. In either case, the file is then read into the ZipFile instance. The app can then enumerate the entries or can modify the zip file, for example adding entries, removing entries, changing comments, and so on.

One advantage to this parameterized constructor: it allows applications to use the same code to add items to a zip archive, regardless of whether the zip file exists.

Instances of the ZipFile class are not multi-thread safe. You may not party on a single instance with multiple threads. You may have multiple threads that each use a distinct ZipFile instance, or you can synchronize multi-thread access to a single instance.

By the way, since DotNetZip is so easy to use, don't you think you should donate $5 or $10?

Exceptions

ZipException

Thrown if name refers to an existing file that is not a valid zip file.

ZipFile(string, TextWriter)

Creates a new ZipFile instance, using the specified name for the filename, and the specified status message writer.

public ZipFile(string fileName, TextWriter statusMessageWriter)

Parameters

fileName string

The filename to use for the new zip archive.

statusMessageWriter TextWriter

A TextWriter to use for writing verbose status messages.

Examples

using (ZipFile zip = new ZipFile("Backup.zip", Console.Out))
{
  // Store all files found in the top level directory, into the zip archive.
  // note: this code does not recurse subdirectories!
  // Status messages will be written to Console.Out
  String[] filenames = System.IO.Directory.GetFiles(DirectoryToZip);
  zip.AddFiles(filenames);
  zip.Save();
}
Using zip As New ZipFile("Backup.zip", Console.Out)
    ' Store all files found in the top level directory, into the zip archive.
    ' note: this code does not recurse subdirectories!
    ' Status messages will be written to Console.Out
    Dim filenames As String() = System.IO.Directory.GetFiles(DirectoryToZip)
    zip.AddFiles(filenames)
    zip.Save()
End Using

Remarks

See the documentation on the ZipFile constructor that accepts a single string argument for basic information on all the ZipFile constructors.

This version of the constructor allows the caller to pass in a TextWriter, to which verbose messages will be written during extraction or creation of the zip archive. A console application may wish to pass System.Console.Out to get messages on the Console. A graphical or headless application may wish to capture the messages in a different TextWriter, for example, a StringWriter, and then display the messages in a TextBox, or generate an audit log of ZipFile operations.

To encrypt the data for the files added to the ZipFile instance, set the Password property after creating the ZipFile instance.

Instances of the ZipFile class are not multi-thread safe. You may not party on a single instance with multiple threads. You may have multiple threads that each use a distinct ZipFile instance, or you can synchronize multi-thread access to a single instance.

Exceptions

ZipException

Thrown if name refers to an existing file that is not a valid zip file.

ZipFile(string, TextWriter, Encoding)

Creates a new ZipFile instance, using the specified name for the filename, the specified status message writer, and the specified Encoding.

public ZipFile(string fileName, TextWriter statusMessageWriter, Encoding encoding)

Parameters

fileName string

The filename to use for the new zip archive.

statusMessageWriter TextWriter

A TextWriter to use for writing verbose status messages.

encoding Encoding

The Encoding is used as the default alternate encoding for entries with filenames or comments that cannot be encoded with the IBM437 code page.

Remarks

This constructor works like the ZipFile constructor that accepts a single string argument. See that reference for detail on what this constructor does.

This version of the constructor allows the caller to pass in a TextWriter, and an Encoding. The TextWriter will collect verbose messages that are generated by the library during extraction or creation of the zip archive. A console application may wish to pass System.Console.Out to get messages on the Console. A graphical or headless application may wish to capture the messages in a different TextWriter, for example, a StringWriter, and then display the messages in a TextBox, or generate an audit log of ZipFile operations.

The Encoding is used as the default alternate encoding for entries with filenames or comments that cannot be encoded with the IBM437 code page. This is a equivalent to setting the ProvisionalAlternateEncoding property on the ZipFile instance after construction.

To encrypt the data for the files added to the ZipFile instance, set the Password property after creating the ZipFile instance.

Instances of the ZipFile class are not multi-thread safe. You may not party on a single instance with multiple threads. You may have multiple threads that each use a distinct ZipFile instance, or you can synchronize multi-thread access to a single instance.

Exceptions

ZipException

Thrown if fileName refers to an existing file that is not a valid zip file.

ZipFile(string, Encoding)

Creates a new ZipFile instance, using the specified name for the filename, and the specified Encoding.

public ZipFile(string fileName, Encoding encoding)

Parameters

fileName string

The filename to use for the new zip archive.

encoding Encoding

The Encoding is used as the default alternate encoding for entries with filenames or comments that cannot be encoded with the IBM437 code page.

Remarks

See the documentation on the ZipFile constructor that accepts a single string argument for basic information on all the ZipFile constructors.

The Encoding is used as the default alternate encoding for entries with filenames or comments that cannot be encoded with the IBM437 code page. This is equivalent to setting the ProvisionalAlternateEncoding property on the ZipFile instance after construction.

Instances of the ZipFile class are not multi-thread safe. You may not party on a single instance with multiple threads. You may have multiple threads that each use a distinct ZipFile instance, or you can synchronize multi-thread access to a single instance.

Exceptions

ZipException

Thrown if name refers to an existing file that is not a valid zip file.

ZipFile(Encoding)

Create a zip file, specifying a text Encoding, but without specifying a target filename or stream to save to.

public ZipFile(Encoding encoding)

Parameters

encoding Encoding

The Encoding is used as the default alternate encoding for entries with filenames or comments that cannot be encoded with the IBM437 code page.

Remarks

See the documentation on the ZipFile constructor that accepts a single string argument for basic information on all the ZipFile constructors.

Fields

BufferSizeDefault

Default size of the buffer used for IO.

public static readonly int BufferSizeDefault

Field Value

int

Properties

AddDirectoryWillTraverseReparsePoints

Indicates whether NTFS Reparse Points, like junctions, should be traversed during calls to AddDirectory().

public bool AddDirectoryWillTraverseReparsePoints { get; set; }

Property Value

bool

Examples

using (var zip = new ZipFile())
{
    zip.AddDirectoryWillTraverseReparsePoints = false;
    zip.AddDirectory(dirToZip,"fodder");
    zip.Save(zipFileToCreate);
}

Remarks

By default, calls to AddDirectory() will traverse NTFS reparse points, like mounted volumes, and directory junctions. An example of a junction is the "My Music" directory in Windows Vista. In some cases you may not want DotNetZip to traverse those directories. In that case, set this property to false.

AlternateEncoding

A Text Encoding to use when encoding the filenames and comments for all the ZipEntry items, during a ZipFile.Save() operation.

public Encoding AlternateEncoding { get; set; }

Property Value

Encoding

Remarks

Whether the encoding specified here is used during the save depends on AlternateEncodingUsage.

AlternateEncodingUsage

A flag that tells if and when this instance should apply AlternateEncoding to encode the filenames and comments associated to of ZipEntry objects contained within this instance.

public ZipOption AlternateEncodingUsage { get; set; }

Property Value

ZipOption

BufferSize

Size of the IO buffer used while saving.

public int BufferSize { get; set; }

Property Value

int

Examples

This example shows how you might set a large buffer size for efficiency when dealing with zip entries that are larger than 1gb.

using (ZipFile zip = new ZipFile())
{
    zip.SaveProgress += this.zip1_SaveProgress;
    zip.AddDirectory(directoryToZip, "");
    zip.UseZip64WhenSaving = Zip64Option.Always;
    zip.BufferSize = 65536*8; // 65536 * 8 = 512k
    zip.Save(ZipFileToCreate);
}

Remarks

First, let me say that you really don't need to bother with this. It is here to allow for optimizations that you probably won't make! It will work fine if you don't set or get this property at all. Ok?

Now that we have that out of the way, the fine print: This property affects the size of the buffer that is used for I/O for each entry contained in the zip file. When a file is read in to be compressed, it uses a buffer given by the size here. When you update a zip file, the data for unmodified entries is copied from the first zip file to the other, through a buffer given by the size here.

Changing the buffer size affects a few things: first, for larger buffer sizes, the memory used by the ZipFile, obviously, will be larger during I/O operations. This may make operations faster for very much larger files. Last, for any given entry, when you use a larger buffer there will be fewer progress events during I/O operations, because there's one progress event generated for each time the buffer is filled and then emptied.

The default buffer size is 8k. Increasing the buffer size may speed things up as you compress larger files. But there are no hard-and-fast rules here, eh? You won't know til you test it. And there will be a limit where ever larger buffers actually slow things down. So as I said in the beginning, it's probably best if you don't set or get this property at all.

CaseSensitiveRetrieval

Indicates whether to perform case-sensitive matching on the filename when retrieving entries in the zipfile via the string-based indexer.

public bool CaseSensitiveRetrieval { get; set; }

Property Value

bool

Remarks

The default value is false, which means don't do case-sensitive matching. In other words, retrieving zip["ReadMe.Txt"] is the same as zip["readme.txt"]. It really makes sense to set this to true only if you are not running on Windows, which has case-insensitive filenames. But since this library is not built for non-Windows platforms, in most cases you should just leave this property alone.

CodecBufferSize

Size of the work buffer to use for the ZLIB codec during compression.

public int CodecBufferSize { get; set; }

Property Value

int

Remarks

When doing ZLIB or Deflate compression, the library fills a buffer, then passes it to the compressor for compression. Then the library reads out the compressed bytes. This happens repeatedly until there is no more uncompressed data to compress. This property sets the size of the buffer that will be used for chunk-wise compression. In order for the setting to take effect, your application needs to set this property before calling one of the ZipFile.Save() overloads.

Setting this affects the performance and memory efficiency of compression and decompression. For larger files, setting this to a larger size may improve compression performance, but the exact numbers vary depending on available memory, the size of the streams you are compressing, and a bunch of other variables. I don't have good firm recommendations on how to set it. You'll have to test it yourself. Or just leave it alone and accept the default.

Comment

A comment attached to the zip archive.

public string Comment { get; set; }

Property Value

string

Remarks

This property is read/write. It allows the application to specify a comment for the ZipFile, or read the comment for the ZipFile. After setting this property, changes are only made permanent when you call a Save() method.

According to PKWARE's zip specification, the comment is not encrypted, even if there is a password set on the zip file.

The specification does not describe how to indicate the encoding used on a comment string. Many "compliant" zip tools and libraries use IBM437 as the code page for comments; DotNetZip, too, follows that practice. On the other hand, there are situations where you want a Comment to be encoded with something else, for example using code page 950 "Big-5 Chinese". To fill that need, DotNetZip will encode the comment following the same procedure it follows for encoding filenames: (a) if AlternateEncodingUsage is Never, it uses the default encoding (IBM437). (b) if AlternateEncodingUsage is Always, it always uses the alternate encoding (AlternateEncoding). (c) if AlternateEncodingUsage is AsNecessary, it uses the alternate encoding only if the default encoding is not sufficient for encoding the comment - in other words if decoding the result does not produce the original string. This decision is taken at the time of the call to ZipFile.Save().

When creating a zip archive using this library, it is possible to change the value of AlternateEncoding between each entry you add, and between adding entries and the call to Save(). Don't do this. It will likely result in a zip file that is not readable by any tool or application. For best interoperability, leave AlternateEncoding alone, or specify it only once, before adding any entries to the ZipFile instance.

CompressionLevel

Sets the compression level to be used for entries subsequently added to the zip archive.

public CompressionLevel CompressionLevel { get; set; }

Property Value

CompressionLevel

Remarks

Varying the compression level used on entries can affect the size-vs-speed tradeoff when compression and decompressing data streams or files.

As with some other properties on the ZipFile class, like Password, Encryption, and ZipErrorAction, setting this property on a ZipFile instance will cause the specified CompressionLevel to be used on all ZipEntry items that are subsequently added to the ZipFile instance. If you set this property after you have added items to the ZipFile, but before you have called Save(), those items will not use the specified compression level.

If you do not set this property, the default compression level is used, which normally gives a good balance of compression efficiency and compression speed. In some tests, using BestCompression can double the time it takes to compress, while delivering just a small increase in compression efficiency. This behavior will vary with the type of data you compress. If you are in doubt, just leave this setting alone, and accept the default.

CompressionMethod

The compression method for the zipfile.

public CompressionMethod CompressionMethod { get; set; }

Property Value

CompressionMethod

Remarks

By default, the compression method is CompressionMethod.Deflate.

See Also

Count

Returns the number of entries in the Zip archive.

public int Count { get; }

Property Value

int

DefaultEncoding

The default text encoding used in zip archives. It is numeric 437, also known as IBM437.

public static Encoding DefaultEncoding { get; set; }

Property Value

Encoding
See Also

EmitTimesInUnixFormatWhenSaving

Specifies whether the Creation, Access, and Modified times for entries added to the zip file will be emitted in "Unix(tm) format" when the zip archive is saved.

public bool EmitTimesInUnixFormatWhenSaving { get; set; }

Property Value

bool

Remarks

An application creating a zip archive can use this flag to explicitly specify that the file times for the entries should or should not be stored in the zip archive in the format used by Unix. By default this flag is false, meaning the Unix-format times are not stored in the zip archive.

When adding an entry from a file or directory, the Creation (CreationTime), Access (AccessedTime), and Modified (ModifiedTime) times for the given entry are automatically set from the filesystem values. When adding an entry from a stream or string, all three values are implicitly set to DateTime.Now. Applications can also explicitly set those times by calling SetEntryTimes(DateTime, DateTime, DateTime).

PKWARE's zip specification describes multiple ways to format these times in a zip file. One is the format Windows applications normally use: 100ns ticks since January 1, 1601 UTC. The other is a format Unix applications typically use: seconds since January 1, 1970 UTC. Each format can be stored in an "extra field" in the zip entry when saving the zip archive. The former uses an extra field with a Header Id of 0x000A, while the latter uses a header ID of 0x5455, although you probably don't need to know that.

Not all tools and libraries can interpret these fields. Windows compressed folders is one that can read the Windows Format timestamps, while I believe the Infozip tools can read the Unix format timestamps. Some tools and libraries may be able to read only one or the other. DotNetZip can read or write times in either or both formats.

The times stored are taken from ModifiedTime, AccessedTime, and CreationTime.

This property is not mutually exclusive of the EmitTimesInWindowsFormatWhenSaving property. It is possible and legal and valid to produce a zip file that contains timestamps encoded in the Unix format as well as in the Windows format, in addition to the LastModified time attached to each entry in the zip archive, a time that is always stored in "DOS format". And, notwithstanding the names PKWare uses for these time formats, any of them can be read and written by any computer, on any operating system. But, there are no guarantees that a program running on Mac or Linux will gracefully handle a zip file with "Windows" formatted times, or that an application that does not use DotNetZip but runs on Windows will be able to handle file times in Unix format.

When in doubt, test. Sorry, I haven't got a complete list of tools and which sort of timestamps they can use and will tolerate. If you get any good information and would like to pass it on, please do so and I will include that information in this documentation.

See Also

EmitTimesInWindowsFormatWhenSaving

Specifies whether the Creation, Access, and Modified times for entries added to the zip file will be emitted in “Windows format” when the zip archive is saved.

public bool EmitTimesInWindowsFormatWhenSaving { get; set; }

Property Value

bool

Examples

This example shows how to save a zip file that contains file timestamps in a format normally used by Unix.

using (var zip = new ZipFile())
{
    // produce a zip file the Mac will like
    zip.EmitTimesInWindowsFormatWhenSaving = false;
    zip.EmitTimesInUnixFormatWhenSaving = true;
    zip.AddDirectory(directoryToZip, "files");
    zip.Save(outputFile);
}
Using zip As New ZipFile
    '' produce a zip file the Mac will like
    zip.EmitTimesInWindowsFormatWhenSaving = False
    zip.EmitTimesInUnixFormatWhenSaving = True
    zip.AddDirectory(directoryToZip, "files")
    zip.Save(outputFile)
End Using

Remarks

An application creating a zip archive can use this flag to explicitly specify that the file times for the entries should or should not be stored in the zip archive in the format used by Windows. By default this flag is true, meaning the Windows-format times are stored in the zip archive.

When adding an entry from a file or directory, the Creation (CreationTime), Access (AccessedTime), and Modified (ModifiedTime) times for the given entry are automatically set from the filesystem values. When adding an entry from a stream or string, all three values are implicitly set to DateTime.Now. Applications can also explicitly set those times by calling SetEntryTimes(DateTime, DateTime, DateTime).

PKWARE's zip specification describes multiple ways to format these times in a zip file. One is the format Windows applications normally use: 100ns ticks since January 1, 1601 UTC. The other is a format Unix applications typically use: seconds since January 1, 1970 UTC. Each format can be stored in an "extra field" in the zip entry when saving the zip archive. The former uses an extra field with a Header Id of 0x000A, while the latter uses a header ID of 0x5455, although you probably don't need to know that.

Not all tools and libraries can interpret these fields. Windows compressed folders is one that can read the Windows Format timestamps, while I believe the Infozip tools can read the Unix format timestamps. Some tools and libraries may be able to read only one or the other. DotNetZip can read or write times in either or both formats.

The times stored are taken from ModifiedTime, AccessedTime, and CreationTime.

The value set here applies to all entries subsequently added to the ZipFile.

This property is not mutually exclusive of the EmitTimesInUnixFormatWhenSaving property. It is possible and legal and valid to produce a zip file that contains timestamps encoded in the Unix format as well as in the Windows format, in addition to the LastModified time attached to each entry in the archive, a time that is always stored in "DOS format". And, notwithstanding the names PKWare uses for these time formats, any of them can be read and written by any computer, on any operating system. But, there are no guarantees that a program running on Mac or Linux will gracefully handle a zip file with "Windows" formatted times, or that an application that does not use DotNetZip but runs on Windows will be able to handle file times in Unix format.

When in doubt, test. Sorry, I haven't got a complete list of tools and which sort of timestamps they can use and will tolerate. If you get any good information and would like to pass it on, please do so and I will include that information in this documentation.

See Also

Encryption

The Encryption to use for entries added to the ZipFile.

public EncryptionAlgorithm Encryption { get; set; }

Property Value

EncryptionAlgorithm

Examples

This example creates a zip archive that uses encryption, and then extracts entries from the archive. When creating the zip archive, the ReadMe.txt file is zipped without using a password or encryption. The other files use encryption.

// Create a zip archive with AES Encryption.
using (ZipFile zip = new ZipFile())
{
    zip.AddFile("ReadMe.txt");
    zip.Encryption= EncryptionAlgorithm.WinZipAes256;
    zip.Password= "Top.Secret.No.Peeking!";
    zip.AddFile("7440-N49th.png");
    zip.AddFile("2008-Regional-Sales-Report.pdf");
    zip.Save("EncryptedArchive.zip");
}

// Extract a zip archive that uses AES Encryption.
// You do not need to specify the algorithm during extraction.
using (ZipFile zip = ZipFile.Read("EncryptedArchive.zip"))
{
    zip.Password= "Top.Secret.No.Peeking!";
    zip.ExtractAll("extractDirectory");
}
' Create a zip that uses Encryption.
Using zip As New ZipFile()
    zip.Encryption= EncryptionAlgorithm.WinZipAes256
    zip.Password= "Top.Secret.No.Peeking!"
    zip.AddFile("ReadMe.txt")
    zip.AddFile("7440-N49th.png")
    zip.AddFile("2008-Regional-Sales-Report.pdf")
    zip.Save("EncryptedArchive.zip")
End Using

' Extract a zip archive that uses AES Encryption.
' You do not need to specify the algorithm during extraction.
Using (zip as ZipFile = ZipFile.Read("EncryptedArchive.zip"))
    zip.Password= "Top.Secret.No.Peeking!"
    zip.ExtractAll("extractDirectory")
End Using

Remarks

Set this when creating a zip archive, or when updating a zip archive. The specified Encryption is applied to the entries subsequently added to the ZipFile instance. Applications do not need to set the Encryption property when reading or extracting a zip archive.

If you set this to something other than EncryptionAlgorithm.None, you will also need to set the Password.

As with some other properties on the ZipFile class, like Password and CompressionLevel, setting this property on a ZipFile instance will cause the specified EncryptionAlgorithm to be used on all ZipEntry items that are subsequently added to the ZipFile instance. In other words, if you set this property after you have added items to the ZipFile, but before you have called Save(), those items will not be encrypted or protected with a password in the resulting zip archive. To get a zip archive with encrypted entries, set this property, along with the Password property, before calling AddFile, AddItem, or AddDirectory (etc.) on the ZipFile instance.

If you read a ZipFile, you can modify the Encryption on an encrypted entry, only by setting the Encryption property on the ZipEntry itself. Setting the Encryption property on the ZipFile, once it has been created via a call to ZipFile.Read(), does not affect entries that were previously read.

For example, suppose you read a ZipFile, and there is an encrypted entry. Setting the Encryption property on that ZipFile and then calling Save() on the ZipFile does not update the Encryption used for the entries in the archive. Neither is an exception thrown. Instead, what happens during the Save() is that all previously existing entries are copied through to the new zip archive, with whatever encryption and password that was used when originally creating the zip archive. Upon re-reading that archive, to extract entries, applications should use the original password or passwords, if any.

Suppose an application reads a ZipFile, and there is an encrypted entry. Setting the Encryption property on that ZipFile and then adding new entries (via AddFile(), AddEntry(), etc) and then calling Save() on the ZipFile does not update the Encryption on any of the entries that had previously been in the ZipFile. The Encryption property applies only to the newly-added entries.

See Also

Entries

Returns the readonly collection of entries in the Zip archive.

public ICollection<ZipEntry> Entries { get; }

Property Value

ICollection<ZipEntry>

Remarks

If there are no entries in the current ZipFile, the value returned is a non-null zero-element collection. If there are entries in the zip file, the elements are returned in no particular order.

This is the implied enumerator on the ZipFile class. If you use a ZipFile instance in a context that expects an enumerator, you will get this collection.

See Also

EntriesSorted

Returns a readonly collection of entries in the Zip archive, sorted by FileName.

public ICollection<ZipEntry> EntriesSorted { get; }

Property Value

ICollection<ZipEntry>

Examples

This example fills a Windows Forms ListView with the entries in a zip file.

using (ZipFile zip = ZipFile.Read(zipFile))
{
    foreach (ZipEntry entry in zip.EntriesSorted)
    {
        ListViewItem item = new ListViewItem(n.ToString());
        n++;
        string[] subitems = new string[] {
            entry.FileName.Replace("/","\\"),
            entry.LastModified.ToString("yyyy-MM-dd HH:mm:ss"),
            entry.UncompressedSize.ToString(),
            String.Format("{0,5:F0}%", entry.CompressionRatio),
            entry.CompressedSize.ToString(),
            (entry.UsesEncryption) ? "Y" : "N",
            String.Format("{0:X8}", entry.Crc)};

        foreach (String s in subitems)
        {
            ListViewItem.ListViewSubItem subitem = new ListViewItem.ListViewSubItem();
            subitem.Text = s;
            item.SubItems.Add(subitem);
        }

        this.listView1.Items.Add(item);
    }
}

Remarks

If there are no entries in the current ZipFile, the value returned is a non-null zero-element collection. If there are entries in the zip file, the elements are returned sorted by the name of the entry.

See Also

EntryFileNames

The list of filenames for the entries contained within the zip archive.

public ICollection<string> EntryFileNames { get; }

Property Value

ICollection<string>

The list of strings for the filenames contained within the Zip archive.

Examples

This example shows one way to test if a filename is already contained within a zip archive.

String zipFileToRead= "PackedDocuments.zip";
string candidate = "DatedMaterial.xps";
using (ZipFile zip = new ZipFile(zipFileToRead))
{
  if (zip.EntryFilenames.Contains(candidate))
    Console.WriteLine("The file '{0}' exists in the zip archive '{1}'",
                      candidate,
                      zipFileName);
  else
    Console.WriteLine("The file, '{0}', does not exist in the zip archive '{1}'",
                      candidate,
                      zipFileName);
  Console.WriteLine();
}
Dim zipFileToRead As String = "PackedDocuments.zip"
Dim candidate As String = "DatedMaterial.xps"
Using zip As ZipFile.Read(ZipFileToRead)
    If zip.EntryFilenames.Contains(candidate) Then
        Console.WriteLine("The file '{0}' exists in the zip archive '{1}'", _
                    candidate, _
                    zipFileName)
    Else
      Console.WriteLine("The file, '{0}', does not exist in the zip archive '{1}'", _
                    candidate, _
                    zipFileName)
    End If
    Console.WriteLine
End Using

Remarks

According to the ZIP specification, the names of the entries use forward slashes in pathnames. If you are scanning through the list, you may have to swap forward slashes for backslashes.

See Also

ExtractExistingFile

The action the library should take when extracting a file that already exists.

public ExtractExistingFileAction ExtractExistingFile { get; set; }

Property Value

ExtractExistingFileAction

Remarks

This property affects the behavior of the Extract methods (one of the Extract() or ExtractWithPassword() overloads), when extraction would would overwrite an existing filesystem file. If you do not set this property, the library throws an exception when extracting an entry would overwrite an existing file.

This property has no effect when extracting to a stream, or when the file to be extracted does not already exist.

See Also

FlattenFoldersOnExtract

Indicates whether extracted files should keep their paths as stored in the zip archive.

public bool FlattenFoldersOnExtract { get; set; }

Property Value

bool

Remarks

This property affects Extraction. It is not used when creating zip archives.

With this property set to false, the default, extracting entries from a zip file will create files in the filesystem that have the full path associated to the entry within the zip file. With this property set to true, extracting entries from the zip file results in files with no path: the folders are "flattened."

An example: suppose the zip file contains entries /directory1/file1.txt and /directory2/file2.txt. With FlattenFoldersOnExtract set to false, the files created will be \directory1\file1.txt and \directory2\file2.txt. With the property set to true, the files created are file1.txt and file2.txt.

FullScan

Indicates whether to perform a full scan of the zip file when reading it.

public bool FullScan { get; set; }

Property Value

bool

Examples

This example shows how to read a zip file using the full scan approach, and then save it, thereby producing a corrected zip file.

using (var zip = new ZipFile())
{
    zip.FullScan = true;
    zip.Initialize(zipFileName);
    zip.Save(newName);
}
Using zip As New ZipFile
    zip.FullScan = True
    zip.Initialize(zipFileName)
    zip.Save(newName)
End Using

Remarks

You almost never want to use this property.

When reading a zip file, if this flag is true (True in VB), the entire zip archive will be scanned and searched for entries. For large archives, this can take a very, long time. The much more efficient default behavior is to read the zip directory, which is stored at the end of the zip file. But, in some cases the directory is corrupted and you need to perform a full scan of the zip file to determine the contents of the zip file. This property lets you do that, when necessary.

This flag is effective only when calling Initialize(string). Normally you would read a ZipFile with the static ZipFile.Read method. But you can't set the FullScan property on the ZipFile instance when you use a static factory method like ZipFile.Read.

IgnoreDuplicateFiles

Indicates whether to ignore duplicate files (report only the first entry) when loading a zipfile.

public bool IgnoreDuplicateFiles { get; set; }

Property Value

bool

Remarks

The default value is false, which will try to make all files available (duplicates will have a "copy" suffix appended to their name). Setting this to true prior to using Initialize to read a zipfile will prevent this and instead just ignore the duplicates.

Info

Provides a human-readable string with information about the ZipFile.

public string Info { get; }

Property Value

string

Remarks

The information string contains 10 lines or so, about each ZipEntry, describing whether encryption is in use, the compressed and uncompressed length of the entry, the offset of the entry, and so on. As a result the information string can be very long for zip files that contain many entries.

This information is mostly useful for diagnostic purposes.

InputUsesZip64

Indicates whether the most recent Read() operation read a zip file that uses ZIP64 extensions.

public bool? InputUsesZip64 { get; }

Property Value

bool?

Remarks

This property will return null (Nothing in VB) if you've added an entry after reading the zip file.

this[int]

This is an integer indexer into the Zip archive.

public ZipEntry this[int ix] { get; }

Parameters

ix int

Property Value

ZipEntry

The ZipEntry within the Zip archive at the specified index. If the entry does not exist in the archive, this indexer throws.

Remarks

This property is read-only.

Internally, the ZipEntry instances that belong to the ZipFile are stored in a Dictionary. When you use this indexer the first time, it creates a read-only List<ZipEntry> from the Dictionary.Values Collection. If at any time you modify the set of entries in the ZipFile, either by adding an entry, removing an entry, or renaming an entry, a new List will be created, and the numeric indexes for the remaining entries may be different.

This means you cannot rename any ZipEntry from inside an enumeration of the zip file.

The index value.

this[string]

This is a name-based indexer into the Zip archive.

public ZipEntry this[string fileName] { get; }

Parameters

fileName string

The name of the file, including any directory path, to retrieve from the zip. The filename match is not case-sensitive by default; you can use the CaseSensitiveRetrieval property to change this behavior. The pathname can use forward-slashes or backward slashes.

Property Value

ZipEntry

The ZipEntry within the Zip archive, given by the specified filename. If the named entry does not exist in the archive, this indexer returns null (Nothing in VB).

Examples

This example extracts only the entries in a zip file that are .txt files.

using (ZipFile zip = ZipFile.Read("PackedDocuments.zip"))
{
  foreach (string s1 in zip.EntryFilenames)
  {
    if (s1.EndsWith(".txt"))
      zip[s1].Extract("textfiles");
  }
}
Using zip As ZipFile = ZipFile.Read("PackedDocuments.zip")
    Dim s1 As String
    For Each s1 In zip.EntryFilenames
        If s1.EndsWith(".txt") Then
            zip(s1).Extract("textfiles")
        End If
    Next
End Using

Remarks

This property is read-only.

The CaseSensitiveRetrieval property on the ZipFile determines whether retrieval via this indexer is done via case-sensitive comparisons. By default, retrieval is not case sensitive. This makes sense on Windows, in which filesystems are not case sensitive.

Regardless of case-sensitivity, it is not always the case that this[value].FileName == value. In other words, the FileName property of the ZipEntry retrieved with this indexer, may or may not be equal to the index value.

This is because DotNetZip performs a normalization of filenames passed to this indexer, before attempting to retrieve the item. That normalization includes: removal of a volume letter and colon, swapping backward slashes for forward slashes. So, zip["dir1\\entry1.txt"].FileName == "dir1/entry.txt".

Directory entries in the zip file may be retrieved via this indexer only with names that have a trailing slash. DotNetZip automatically appends a trailing slash to the names of any directory entries added to a zip.

Exceptions

ArgumentException

Thrown if the caller attempts to assign a non-null value to the indexer.

See Also

LibraryVersion

Returns the version number on the DotNetZip assembly.

public static Version LibraryVersion { get; }

Property Value

Version

Remarks

This property is exposed as a convenience. Callers could also get the version value by retrieving GetName().Version on the System.Reflection.Assembly object pointing to the DotNetZip assembly. But sometimes it is not clear which assembly is being loaded. This property makes it clear.

This static property is primarily useful for diagnostic purposes.

MaxOutputSegmentSize

The maximum size of an output segment, when saving a split Zip file.

public int MaxOutputSegmentSize { get; set; }

Property Value

int

Remarks

Make sure you do not read from this field if you've set the value using MaxOutputSegmentSize64

Set this to a non-zero value before calling Save() or Save(string) to specify that the ZipFile should be saved as a split archive, also sometimes called a spanned archive. Some also call them multi-file archives.

A split zip archive is saved in a set of discrete filesystem files, rather than in a single file. This is handy when transmitting the archive in email or some other mechanism that has a limit to the size of each file. The first file in a split archive will be named basename.z01, the second will be named basename.z02, and so on. The final file is named basename.zip. According to the zip specification from PKWare, the minimum value is 65536, for a 64k segment size. The maximum number of segments allows in a split archive is 99.

The value of this property determines the maximum size of a split segment when writing a split archive. For example, suppose you have a ZipFile that would save to a single file of 200k. If you set the MaxOutputSegmentSize to 65536 before calling Save(), you will get four distinct output files. On the other hand if you set this property to 256k, then you will get a single-file archive for that ZipFile.

The size of each split output file will be as large as possible, up to the maximum size set here. The zip specification requires that some data fields in a zip archive may not span a split boundary, and an output segment may be smaller than the maximum if necessary to avoid that problem. Also, obviously the final segment of the archive may be smaller than the maximum segment size. Segments will never be larger than the value set with this property.

You can save a split Zip file only when saving to a regular filesystem file. It's not possible to save a split zip file as a self-extracting archive, nor is it possible to save a split zip file to a stream. When saving to a SFX or to a Stream, this property is ignored.

About interoperability: Split or spanned zip files produced by DotNetZip can be read by WinZip or PKZip, and vice-versa. Segmented zip files may not be readable by other tools, if those other tools don't support zip spanning or splitting. When in doubt, test. I don't believe Windows Explorer can extract a split archive.

This property has no effect when reading a split archive. You can read a split archive in the normal way with DotNetZip.

When saving a zip file, if you want a regular zip file rather than a split zip file, don't set this property, or set it to Zero.

If you read a split archive, with Read(string) and then subsequently call ZipFile.Save(), unless you set this property before calling Save(), you will get a normal, single-file archive.

See Also

MaxOutputSegmentSize64

The maximum size of an output segment, when saving a split Zip file.

public long MaxOutputSegmentSize64 { get; set; }

Property Value

long

Remarks

If you set this value, make sure you do not accidently use MaxOutputSegmentSize in your code

Set this to a non-zero value before calling Save() or Save(string) to specify that the ZipFile should be saved as a split archive, also sometimes called a spanned archive. Some also call them multi-file archives.

A split zip archive is saved in a set of discrete filesystem files, rather than in a single file. This is handy when transmitting the archive in email or some other mechanism that has a limit to the size of each file. The first file in a split archive will be named basename.z01, the second will be named basename.z02, and so on. The final file is named basename.zip. According to the zip specification from PKWare, the minimum value is 65536, for a 64k segment size. The maximum number of segments allows in a split archive is 99.

The value of this property determines the maximum size of a split segment when writing a split archive. For example, suppose you have a ZipFile that would save to a single file of 200k. If you set the MaxOutputSegmentSize to 65536 before calling Save(), you will get four distinct output files. On the other hand if you set this property to 256k, then you will get a single-file archive for that ZipFile.

The size of each split output file will be as large as possible, up to the maximum size set here. The zip specification requires that some data fields in a zip archive may not span a split boundary, and an output segment may be smaller than the maximum if necessary to avoid that problem. Also, obviously the final segment of the archive may be smaller than the maximum segment size. Segments will never be larger than the value set with this property.

You can save a split Zip file only when saving to a regular filesystem file. It's not possible to save a split zip file as a self-extracting archive, nor is it possible to save a split zip file to a stream. When saving to a SFX or to a Stream, this property is ignored.

About interoperability: Split or spanned zip files produced by DotNetZip can be read by WinZip or PKZip, and vice-versa. Segmented zip files may not be readable by other tools, if those other tools don't support zip spanning or splitting. When in doubt, test. I don't believe Windows Explorer can extract a split archive.

This property has no effect when reading a split archive. You can read a split archive in the normal way with DotNetZip.

When saving a zip file, if you want a regular zip file rather than a split zip file, don't set this property, or set it to Zero.

If you read a split archive, with Read(string) and then subsequently call ZipFile.Save(), unless you set this property before calling Save(), you will get a normal, single-file archive.

See Also

Name

The name of the ZipFile, on disk.

public string Name { get; set; }

Property Value

string

Remarks

When the ZipFile instance was created by reading an archive using one of the ZipFile.Read methods, this property represents the name of the zip file that was read. When the ZipFile instance was created by using the no-argument constructor, this value is null (Nothing in VB).

If you use the no-argument constructor, and you then explicitly set this property, when you call Save(), this name will specify the name of the zip file created. Doing so is equivalent to calling Save(string). When instantiating a ZipFile by reading from a stream or byte array, the Name property remains null. When saving to a stream, the Name property is implicitly set to null.

NumberOfSegmentsForMostRecentSave

Returns the number of segments used in the most recent Save() operation.

public int NumberOfSegmentsForMostRecentSave { get; }

Property Value

int

Remarks

This is normally zero, unless you have set the MaxOutputSegmentSize property. If you have set MaxOutputSegmentSize, and then you save a file, after the call to Save() completes, you can read this value to learn the number of segments that were created.

If you call Save("Archive.zip"), and it creates 5 segments, then you will have filesystem files named Archive.z01, Archive.z02, Archive.z03, Archive.z04, and Archive.zip, and the value of this property will be 5.

See Also

OutputUsedZip64

Indicates whether the most recent Save() operation used ZIP64 extensions.

public bool? OutputUsedZip64 { get; }

Property Value

bool?

Remarks

The use of ZIP64 extensions within an archive is not always necessary, and for interoperability concerns, it may be desired to NOT use ZIP64 if possible. The UseZip64WhenSaving property can be set to use ZIP64 extensions only when necessary. In those cases, Sometimes applications want to know whether a Save() actually used ZIP64 extensions. Applications can query this read-only property to learn whether ZIP64 has been used in a just-saved ZipFile.

The value is null (or Nothing in VB) if the archive has not been saved.

Non-null values (HasValue is true) indicate whether ZIP64 extensions were used during the most recent Save() operation. The ZIP64 extensions may have been used as required by any particular entry because of its uncompressed or compressed size, or because the archive is larger than 4294967295 bytes, or because there are more than 65534 entries in the archive, or because the UseZip64WhenSaving property was set to Always, or because the UseZip64WhenSaving property was set to AsNecessary and the output stream was not seekable. The value of this property does not indicate the reason the ZIP64 extensions were used.

See Also

ParallelDeflateMaxBufferPairs

The maximum number of buffer pairs to use when performing parallel compression.

public int ParallelDeflateMaxBufferPairs { get; set; }

Property Value

int

Remarks

This property sets an upper limit on the number of memory buffer pairs to create when performing parallel compression. The implementation of the parallel compression stream allocates multiple buffers to facilitate parallel compression. As each buffer fills up, the stream uses ThreadPool.QueueUserWorkItem() to compress those buffers in a background threadpool thread. After a buffer is compressed, it is re-ordered and written to the output stream.

A higher number of buffer pairs enables a higher degree of parallelism, which tends to increase the speed of compression on multi-cpu computers. On the other hand, a higher number of buffer pairs also implies a larger memory consumption, more active worker threads, and a higher cpu utilization for any compression. This property enables the application to limit its memory consumption and CPU utilization behavior depending on requirements.

For each compression "task" that occurs in parallel, there are 2 buffers allocated: one for input and one for output. This property sets a limit for the number of pairs. The total amount of storage space allocated for buffering will then be (N*S*2), where N is the number of buffer pairs, S is the size of each buffer (BufferSize). By default, DotNetZip allocates 4 buffer pairs per CPU core, so if your machine has 4 cores, and you retain the default buffer size of 128k, then the ParallelDeflateOutputStream will use 4 * 4 * 2 * 128kb of buffer memory in total, or 4mb, in blocks of 128kb. If you then set this property to 8, then the number will be 8 * 2 * 128kb of buffer memory, or 2mb.

CPU utilization will also go up with additional buffers, because a larger number of buffer pairs allows a larger number of background threads to compress in parallel. If you find that parallel compression is consuming too much memory or CPU, you can adjust this value downward.

The default value is 16. Different values may deliver better or worse results, depending on your priorities and the dynamic performance characteristics of your storage and compute resources.

This property is not the number of buffer pairs to use; it is an upper limit. An illustration: Suppose you have an application that uses the default value of this property (which is 16), and it runs on a machine with 2 CPU cores. In that case, DotNetZip will allocate 4 buffer pairs per CPU core, for a total of 8 pairs. The upper limit specified by this property has no effect.

The application can set this value at any time before calling ZipFile.Save().

See Also

ParallelDeflateThreshold

The size threshold for an entry, above which a parallel deflate is used.

public long ParallelDeflateThreshold { get; set; }

Property Value

long

Remarks

DotNetZip will use multiple threads to compress any ZipEntry, if the entry is larger than the given size. Zero means "always use parallel deflate", while -1 means "never use parallel deflate". The default value for this property is 512k. Aside from the special values of 0 and 1, the minimum value is 65536.

If the entry size cannot be known before compression, as with a read-forward stream, then Parallel deflate will never be performed, unless the value of this property is zero.

A parallel deflate operations will speed up the compression of large files, on computers with multiple CPUs or multiple CPU cores. For files above 1mb, on a dual core or dual-cpu (2p) machine, the time required to compress the file can be 70% of the single-threaded deflate. For very large files on 4p machines the compression can be done in 30% of the normal time. The downside is that parallel deflate consumes extra memory during the deflate, and the deflation is not as effective.

Parallel deflate tends to yield slightly less compression when compared to as single-threaded deflate; this is because the original data stream is split into multiple independent buffers, each of which is compressed in parallel. But because they are treated independently, there is no opportunity to share compression dictionaries. For that reason, a deflated stream may be slightly larger when compressed using parallel deflate, as compared to a traditional single-threaded deflate. Sometimes the increase over the normal deflate is as much as 5% of the total compressed size. For larger files it can be as small as 0.1%.

Multi-threaded compression does not give as much an advantage when using Encryption. This is primarily because encryption tends to slow down the entire pipeline. Also, multi-threaded compression gives less of an advantage when using lower compression levels, for example BestSpeed. You may have to perform some tests to determine the best approach for your situation.

See Also

Password

Sets the password to be used on the ZipFile instance.

public string Password { set; }

Property Value

string

Examples

This example creates a zip file, using password protection for the entries, and then extracts the entries from the zip file. When creating the zip file, the Readme.txt file is not protected with a password, but the other two are password-protected as they are saved. During extraction, each file is extracted with the appropriate password.

// create a file with encryption
using (ZipFile zip = new ZipFile())
{
    zip.AddFile("ReadMe.txt");
    zip.Password= "!Secret1";
    zip.AddFile("MapToTheSite-7440-N49th.png");
    zip.AddFile("2008-Regional-Sales-Report.pdf");
    zip.Save("EncryptedArchive.zip");
}

// extract entries that use encryption using (ZipFile zip = ZipFile.Read("EncryptedArchive.zip")) { zip.Password= "!Secret1"; zip.ExtractAll("extractDir"); }

Using zip As New ZipFile
    zip.AddFile("ReadMe.txt")
    zip.Password = "123456!"
    zip.AddFile("MapToTheSite-7440-N49th.png")
    zip.Password= "!Secret1";
    zip.AddFile("2008-Regional-Sales-Report.pdf")
    zip.Save("EncryptedArchive.zip")
End Using


' extract entries that use encryption
Using (zip as ZipFile = ZipFile.Read("EncryptedArchive.zip"))
    zip.Password= "!Secret1"
    zip.ExtractAll("extractDir")
End Using

Remarks

When writing a zip archive, this password is applied to the entries, not to the zip archive itself. It applies to any ZipEntry subsequently added to the ZipFile, using one of the AddFile, AddDirectory, AddEntry, or AddItem methods, etc. When reading a zip archive, this property applies to any entry subsequently extracted from the ZipFile using one of the Extract methods on the ZipFile class.

When writing a zip archive, keep this in mind: though the password is set on the ZipFile object, according to the Zip spec, the "directory" of the archive - in other words the list of entries or files contained in the archive - is not encrypted with the password, or protected in any way. If you set the Password property, the password actually applies to individual entries that are added to the archive, subsequent to the setting of this property. The list of filenames in the archive that is eventually created will appear in clear text, but the contents of the individual files are encrypted. This is how Zip encryption works.

One simple way around this limitation is to simply double-wrap sensitive filenames: Store the files in a zip file, and then store that zip file within a second, "outer" zip file. If you apply a password to the outer zip file, then readers will be able to see that the outer zip file contains an inner zip file. But readers will not be able to read the directory or file list of the inner zip file.

If you set the password on the ZipFile, and then add a set of files to the archive, then each entry is encrypted with that password. You may also want to change the password between adding different entries. If you set the password, add an entry, then set the password to null (Nothing in VB), and add another entry, the first entry is encrypted and the second is not. If you call AddFile(), then set the Password property, then call ZipFile.Save, the file added will not be password-protected, and no warning will be generated.

When setting the Password, you may also want to explicitly set the Encryption property, to specify how to encrypt the entries added to the ZipFile. If you set the Password to a non-null value and do not set Encryption, then PKZip 2.0 ("Weak") encryption is used. This encryption is relatively weak but is very interoperable. If you set the password to a null value (Nothing in VB), Encryption is reset to None.

All of the preceding applies to writing zip archives, in other words when you use one of the Save methods. To use this property when reading or an existing ZipFile, do the following: set the Password property on the ZipFile, then call one of the Extract() overloads on the ZipEntry. In this case, the entry is extracted using the Password that is specified on the ZipFile instance. If you have not set the Password property, then the password is null, and the entry is extracted with no password.

If you set the Password property on the ZipFile, then call Extract() an entry that has not been encrypted with a password, the password is not used for that entry, and the ZipEntry is extracted as normal. In other words, the password is used only if necessary.

The ZipEntry class also has a Password property. It takes precedence over this property on the ZipFile. Typically, you would use the per-entry Password when most entries in the zip archive use one password, and a few entries use a different password. If all entries in the zip file use the same password, then it is simpler to just set this property on the ZipFile itself, whether creating a zip archive or extracting a zip archive.

See Also

ProvisionalAlternateEncoding

The text encoding to use when writing new entries to the ZipFile, for those entries that cannot be encoded with the default (IBM437) encoding; or, the text encoding that was used when reading the entries from the ZipFile.

[Obsolete("use AlternateEncoding instead.")]
public Encoding ProvisionalAlternateEncoding { get; set; }

Property Value

Encoding

Examples

This example shows how to read a zip file using the Big-5 Chinese code page (950), and extract each entry in the zip file. For this code to work as desired, the Zipfile must have been created using the big5 code page (CP950). This is typical, for example, when using WinRar on a machine with CP950 set as the default code page. In that case, the names of entries within the Zip archive will be stored in that code page, and reading the zip archive must be done using that code page. If the application did not use the correct code page in ZipFile.Read(), then names of entries within the zip archive would not be correctly retrieved.

using (var zip = ZipFile.Read(zipFileName, System.Text.Encoding.GetEncoding("big5")))
{
    // retrieve and extract an entry using a name encoded with CP950
    zip[MyDesiredEntry].Extract("unpack");
}
Using zip As ZipFile = ZipFile.Read(ZipToExtract, System.Text.Encoding.GetEncoding("big5"))
    ' retrieve and extract an entry using a name encoded with CP950
    zip(MyDesiredEntry).Extract("unpack")
End Using

Remarks

In its zip specification, PKWare describes two options for encoding filenames and comments: using IBM437 or UTF-8. But, some archiving tools or libraries do not follow the specification, and instead encode characters using the system default code page. For example, WinRAR when run on a machine in Shanghai may encode filenames with the Big-5 Chinese (950) code page. This behavior is contrary to the Zip specification, but it occurs anyway.

When using DotNetZip to write zip archives that will be read by one of these other archivers, set this property to specify the code page to use when encoding the FileName and Comment for each ZipEntry in the zip file, for values that cannot be encoded with the default codepage for zip files, IBM437. This is why this property is "provisional". In all cases, IBM437 is used where possible, in other words, where no loss of data would result. It is possible, therefore, to have a given entry with a Comment encoded in IBM437 and a FileName encoded with the specified "provisional" codepage.

Be aware that a zip file created after you've explicitly set the ProvisionalAlternateEncoding property to a value other than IBM437 may not be compliant to the PKWare specification, and may not be readable by compliant archivers. On the other hand, many (most?) archivers are non-compliant and can read zip files created in arbitrary code pages. The trick is to use or specify the proper codepage when reading the zip.

When creating a zip archive using this library, it is possible to change the value of ProvisionalAlternateEncoding between each entry you add, and between adding entries and the call to Save(). Don't do this. It will likely result in a zipfile that is not readable. For best interoperability, either leave ProvisionalAlternateEncoding alone, or specify it only once, before adding any entries to the ZipFile instance. There is one exception to this recommendation, described later.

When using an arbitrary, non-UTF8 code page for encoding, there is no standard way for the creator application - whether DotNetZip, WinZip, WinRar, or something else - to formally specify in the zip file which codepage has been used for the entries. As a result, readers of zip files are not able to inspect the zip file and determine the codepage that was used for the entries contained within it. It is left to the application or user to determine the necessary codepage when reading zip files encoded this way. In other words, if you explicitly specify the codepage when you create the zipfile, you must explicitly specify the same codepage when reading the zipfile.

The way you specify the code page to use when reading a zip file varies depending on the tool or library you use to read the zip. In DotNetZip, you use a ZipFile.Read() method that accepts an encoding parameter. It isn't possible with Windows Explorer, as far as I know, to specify an explicit codepage to use when reading a zip. If you use an incorrect codepage when reading a zipfile, you will get entries with filenames that are incorrect, and the incorrect filenames may even contain characters that are not legal for use within filenames in Windows. Extracting entries with illegal characters in the filenames will lead to exceptions. It's too bad, but this is just the way things are with code pages in zip files. Caveat Emptor.

Example: Suppose you create a zipfile that contains entries with filenames that have Danish characters. If you use ProvisionalAlternateEncoding equal to "iso-8859-1" (cp 28591), the filenames will be correctly encoded in the zip. But, to read that zipfile correctly, you have to specify the same codepage at the time you read it. If try to read that zip file with Windows Explorer or another application that is not flexible with respect to the codepage used to decode filenames in zipfiles, you will get a filename like "Infďż˝.txt".

When using DotNetZip to read a zip archive, and the zip archive uses an arbitrary code page, you must specify the encoding to use before or when the Zipfile is READ. This means you must use a ZipFile.Read() method that allows you to specify a System.Text.Encoding parameter. Setting the ProvisionalAlternateEncoding property after your application has read in the zip archive will not affect the entry names of entries that have already been read in.

And now, the exception to the rule described above. One strategy for specifying the code page for a given zip file is to describe the code page in a human-readable form in the Zip comment. For example, the comment may read "Entries in this archive are encoded in the Big5 code page". For maximum interoperability, the zip comment in this case should be encoded in the default, IBM437 code page. In this case, the zip comment is encoded using a different page than the filenames. To do this, Specify ProvisionalAlternateEncoding to your desired region-specific code page, once before adding any entries, and then reset ProvisionalAlternateEncoding to IBM437 before setting the Comment property and calling Save().

See Also

RequiresZip64

Indicates whether the archive requires ZIP64 extensions.

public bool? RequiresZip64 { get; }

Property Value

bool?

Remarks

This property is null (or Nothing in VB) if the archive has not been saved, and there are fewer than 65334 ZipEntry items contained in the archive.

The Value is true if any of the following four conditions holds: the uncompressed size of any entry is larger than 0xFFFFFFFF; the compressed size of any entry is larger than 0xFFFFFFFF; the relative offset of any entry within the zip archive is larger than 0xFFFFFFFF; or there are more than 65534 entries in the archive. (0xFFFFFFFF = 4,294,967,295). The result may not be known until a Save() is attempted on the zip archive. The Value of this Nullable property may be set only AFTER one of the Save() methods has been called.

If none of the four conditions holds, and the archive has been saved, then the Value is false.

A Value of false does not indicate that the zip archive, as saved, does not use ZIP64. It merely indicates that ZIP64 is not required. An archive may use ZIP64 even when not required if the UseZip64WhenSaving property is set to Always, or if the UseZip64WhenSaving property is set to AsNecessary and the output stream was not seekable. Use the OutputUsedZip64 property to determine if the most recent Save() method resulted in an archive that utilized the ZIP64 extensions.

See Also

SetCompression

A callback that allows the application to specify the compression level to use for entries subsequently added to the zip archive.

public SetCompressionCallback SetCompression { get; set; }

Property Value

SetCompressionCallback

Remarks

With this callback, the DotNetZip library allows the application to determine whether compression will be used, at the time of the Save. This may be useful if the application wants to favor speed over size, and wants to defer the decision until the time of Save.

Typically applications set the CompressionLevel property on the ZipFile or on each ZipEntry to determine the level of compression used. This is done at the time the entry is added to the ZipFile. Setting the property to CompressionLevel.None means no compression will be used.

This callback allows the application to defer the decision on the CompressionLevel to use, until the time of the call to ZipFile.Save(). The callback is invoked once per ZipEntry, at the time the data for the entry is being written out as part of a Save() operation. The application can use whatever criteria it likes in determining the level to return. For example, an application may wish that no .mp3 files should be compressed, because they are already compressed and the extra compression is not worth the CPU time incurred, and so can return None for all .mp3 entries.

The library determines whether compression will be attempted for an entry this way: If the entry is a zero length file, or a directory, no compression is used. Otherwise, if this callback is set, it is invoked and the CompressionLevel is set to the return value. If this callback has not been set, then the previously set value for CompressionLevel is used.

SortEntriesBeforeSaving

Whether to sort the ZipEntries before saving the file.

public bool SortEntriesBeforeSaving { get; set; }

Property Value

bool

Examples

using (var zip = new ZipFile())
{
    zip.AddFiles(filesToAdd);
    zip.SortEntriesBeforeSaving = true;
    zip.Save(name);
}
Using zip As New ZipFile
    zip.AddFiles(filesToAdd)
    zip.SortEntriesBeforeSaving = True
    zip.Save(name)
End Using

Remarks

The default is false. If you have a large number of zip entries, the sort alone can consume significant time.

StatusMessageTextWriter

Gets or sets the TextWriter to which status messages are delivered for the instance.

public TextWriter StatusMessageTextWriter { get; set; }

Property Value

TextWriter

Examples

In this example, a console application instantiates a ZipFile, then sets the StatusMessageTextWriter to Console.Out. At that point, all verbose status messages for that ZipFile are sent to the console.

using (ZipFile zip= ZipFile.Read(FilePath))
{
  zip.StatusMessageTextWriter= System.Console.Out;
  // messages are sent to the console during extraction
  zip.ExtractAll();
}
Using zip As ZipFile = ZipFile.Read(FilePath)
  zip.StatusMessageTextWriter= System.Console.Out
  'Status Messages will be sent to the console during extraction
  zip.ExtractAll()
End Using

In this example, a Windows Forms application instantiates a ZipFile, then sets the StatusMessageTextWriter to a StringWriter. At that point, all verbose status messages for that ZipFile are sent to the StringWriter.

var sw = new System.IO.StringWriter();
using (ZipFile zip= ZipFile.Read(FilePath))
{
  zip.StatusMessageTextWriter= sw;
  zip.ExtractAll();
}
Console.WriteLine("{0}", sw.ToString());
Dim sw as New System.IO.StringWriter
Using zip As ZipFile = ZipFile.Read(FilePath)
  zip.StatusMessageTextWriter= sw
  zip.ExtractAll()
End Using
'Status Messages are now available in sw

Remarks

If the TextWriter is set to a non-null value, then verbose output is sent to the TextWriter during Add, Read, Save and Extract operations. Typically, console applications might use Console.Out and graphical or headless applications might use a System.IO.StringWriter. The output of this is suitable for viewing by humans.

Strategy

The compression strategy to use for all entries.

public CompressionStrategy Strategy { get; set; }

Property Value

CompressionStrategy

Remarks

Set the Strategy used by the ZLIB-compatible compressor, when compressing entries using the DEFLATE method. Different compression strategies work better on different sorts of data. The strategy parameter can affect the compression ratio and the speed of compression but not the correctness of the compresssion. For more information see CompressionStrategy.

TempFileFolder

Gets or sets the name for the folder to store the temporary file this library writes when saving a zip archive.

public string TempFileFolder { get; set; }

Property Value

string

Remarks

This library will create a temporary file when saving a Zip archive to a file. This file is written when calling one of the Save() methods that does not save to a stream, or one of the SaveSelfExtractor() methods.

By default, the library will create the temporary file in the directory specified for the file itself, via the Name property or via the Save(string) method.

Setting this property allows applications to override this default behavior, so that the library will create the temporary file in the specified folder. For example, to have the library create the temporary file in the current working directory, regardless where the ZipFile is saved, specfy ".". To revert to the default behavior, set this property to null (Nothing in VB).

When setting the property to a non-null value, the folder specified must exist; if it does not an exception is thrown. The application should have write and delete permissions on the folder. The permissions are not explicitly checked ahead of time; if the application does not have the appropriate rights, an exception will be thrown at the time Save() is called.

There is no temporary file created when reading a zip archive. When saving to a Stream, there is no temporary file created. For example, if the application is an ASP.NET application and calls Save() specifying the Response.OutputStream as the output stream, there is no temporary file created.

Exceptions

FileNotFoundException

Thrown when setting the property if the directory does not exist.

UseUnicodeAsNecessary

Indicates whether to encode entry filenames and entry comments using Unicode (UTF-8).

[Obsolete("Beginning with v1.9.1.6 of DotNetZip, this property is obsolete.  It will be removed in a future version of the library. Your applications should  use AlternateEncoding and AlternateEncodingUsage instead.")]
public bool UseUnicodeAsNecessary { get; set; }

Property Value

bool

Remarks

The PKWare zip specification provides for encoding file names and file comments in either the IBM437 code page, or in UTF-8. This flag selects the encoding according to that specification. By default, this flag is false, and filenames and comments are encoded into the zip file in the IBM437 codepage. Setting this flag to true will specify that filenames and comments that cannot be encoded with IBM437 will be encoded with UTF-8.

Zip files created with strict adherence to the PKWare specification with respect to UTF-8 encoding can contain entries with filenames containing any combination of Unicode characters, including the full range of characters from Chinese, Latin, Hebrew, Greek, Cyrillic, and many other alphabets. However, because at this time, the UTF-8 portion of the PKWare specification is not broadly supported by other zip libraries and utilities, such zip files may not be readable by your favorite zip tool or archiver. In other words, interoperability will decrease if you set this flag to true.

In particular, Zip files created with strict adherence to the PKWare specification with respect to UTF-8 encoding will not work well with Explorer in Windows XP or Windows Vista, because Windows compressed folders, as far as I know, do not support UTF-8 in zip files. Vista can read the zip files, but shows the filenames incorrectly. Unpacking from Windows Vista Explorer will result in filenames that have rubbish characters in place of the high-order UTF-8 bytes.

Also, zip files that use UTF-8 encoding will not work well with Java applications that use the java.util.zip classes, as of v5.0 of the Java runtime. The Java runtime does not correctly implement the PKWare specification in this regard.

As a result, we have the unfortunate situation that "correct" behavior by the DotNetZip library with regard to Unicode encoding of filenames during zip creation will result in zip files that are readable by strictly compliant and current tools (for example the most recent release of the commercial WinZip tool); but these zip files will not be readable by various other tools or libraries, including Windows Explorer.

The DotNetZip library can read and write zip files with UTF8-encoded entries, according to the PKware spec. If you use DotNetZip for both creating and reading the zip file, and you use UTF-8, there will be no loss of information in the filenames. For example, using a self-extractor created by this library will allow you to unpack files correctly with no loss of information in the filenames.

If you do not set this flag, it will remain false. If this flag is false, your ZipFile will encode all filenames and comments using the IBM437 codepage. This can cause "loss of information" on some filenames, but the resulting zipfile will be more interoperable with other utilities. As an example of the loss of information, diacritics can be lost. The o-tilde character will be down-coded to plain o. The c with a cedilla (Unicode 0xE7) used in Portugese will be downcoded to a c. Likewise, the O-stroke character (Unicode 248), used in Danish and Norwegian, will be down-coded to plain o. Chinese characters cannot be represented in codepage IBM437; when using the default encoding, Chinese characters in filenames will be represented as ?. These are all examples of "information loss".

The loss of information associated to the use of the IBM437 encoding is inconvenient, and can also lead to runtime errors. For example, using IBM437, any sequence of 4 Chinese characters will be encoded as ????. If your application creates a ZipFile, then adds two files, each with names of four Chinese characters each, this will result in a duplicate filename exception. In the case where you add a single file with a name containing four Chinese characters, calling Extract() on the entry that has question marks in the filename will result in an exception, because the question mark is not legal for use within filenames on Windows. These are just a few examples of the problems associated to loss of information.

This flag is independent of the encoding of the content within the entries in the zip file. Think of the zip file as a container - it supports an encoding. Within the container are other "containers" - the file entries themselves. The encoding within those entries is independent of the encoding of the zip archive container for those entries.

Rather than specify the encoding in a binary fashion using this flag, an application can specify an arbitrary encoding via the ProvisionalAlternateEncoding property. Setting the encoding explicitly when creating zip archives will result in non-compliant zip files that, curiously, are fairly interoperable. The challenge is, the PKWare specification does not provide for a way to specify that an entry in a zip archive uses a code page that is neither IBM437 nor UTF-8. Therefore if you set the encoding explicitly when creating a zip archive, you must take care upon reading the zip archive to use the same code page. If you get it wrong, the behavior is undefined and may result in incorrect filenames, exceptions, stomach upset, hair loss, and acne.

See Also

UseZip64WhenSaving

Specify whether to use ZIP64 extensions when saving a zip archive.

public Zip64Option UseZip64WhenSaving { get; set; }

Property Value

Zip64Option

Remarks

When creating a zip file, the default value for the property is Never. AsNecessary is safest, in the sense that you will not get an Exception if a pre-ZIP64 limit is exceeded.

You may set the property at any time before calling Save().

When reading a zip file via the Zipfile.Read() method, DotNetZip will properly read ZIP64-endowed zip archives, regardless of the value of this property. DotNetZip will always read ZIP64 archives. This property governs only whether DotNetZip will write them. Therefore, when updating archives, be careful about setting this property after reading an archive that may use ZIP64 extensions.

An interesting question is, if you have set this property to AsNecessary, and then successfully saved, does the resulting archive use ZIP64 extensions or not? To learn this, check the OutputUsedZip64 property, after calling Save().

Have you thought about donating?

See Also

ZipErrorAction

The action the library should take when an error is encountered while opening or reading files as they are saved into a zip archive.

public ZipErrorAction ZipErrorAction { get; set; }

Property Value

ZipErrorAction

Examples

This example shows how to tell DotNetZip to skip any files for which an error is generated during the Save().

Public Sub SaveZipFile()
    Dim SourceFolder As String = "fodder"
    Dim DestFile As String =  "eHandler.zip"
    Dim sw as New StringWriter
    Using zipArchive As ZipFile = New ZipFile
        ' Tell DotNetZip to skip any files for which it encounters an error
        zipArchive.ZipErrorAction = ZipErrorAction.Skip
        zipArchive.StatusMessageTextWriter = sw
        zipArchive.AddDirectory(SourceFolder)
        zipArchive.Save(DestFile)
    End Using
    ' examine sw here to see any messages
End Sub

Remarks

Errors can occur as a file is being saved to the zip archive. For example, the File.Open may fail, or a File.Read may fail, because of lock conflicts or other reasons.

The first problem might occur after having called AddDirectory() on a directory that contains a Clipper .dbf file; the file is locked by Clipper and cannot be opened for read by another process. An example of the second problem might occur when trying to zip a .pst file that is in use by Microsoft Outlook. Outlook locks a range on the file, which allows other processes to open the file, but not read it in its entirety.

This property tells DotNetZip what you would like to do in the case of these errors. The primary options are: ZipErrorAction.Throw to throw an exception (this is the default behavior if you don't set this property); ZipErrorAction.Skip to Skip the file for which there was an error and continue saving; ZipErrorAction.Retry to Retry the entry that caused the problem; or ZipErrorAction.InvokeErrorEvent to invoke an event handler.

This property is implicitly set to ZipErrorAction.InvokeErrorEvent if you add a handler to the ZipError event. If you set this property to something other than ZipErrorAction.InvokeErrorEvent, then the ZipError event is implicitly cleared. What it means is you can set one or the other (or neither), depending on what you want, but you never need to set both.

As with some other properties on the ZipFile class, like Password, Encryption, and CompressionLevel, setting this property on a ZipFile instance will cause the specified ZipErrorAction to be used on all ZipEntry items that are subsequently added to the ZipFile instance. If you set this property after you have added items to the ZipFile, but before you have called Save(), those items will not use the specified error handling action.

If you want to handle any errors that occur with any entry in the zip file in the same way, then set this property once, before adding any entries to the zip archive.

If you set this property to ZipErrorAction.Skip and you'd like to learn which files may have been skipped after a Save(), you can set the StatusMessageTextWriter on the ZipFile before calling Save(). A message will be emitted into that writer for each skipped file, if any.

See Also

Methods

AddDirectory(string)

Adds the contents of a filesystem directory to a Zip file archive.

public ZipEntry AddDirectory(string directoryName)

Parameters

directoryName string

The name of the directory to add.

Returns

ZipEntry

The ZipEntry added.

Remarks

The name of the directory may be a relative path or a fully-qualified path. Any files within the named directory are added to the archive. Any subdirectories within the named directory are also added to the archive, recursively.

Top-level entries in the named directory will appear as top-level entries in the zip archive. Entries in subdirectories in the named directory will result in entries in subdirectories in the zip archive.

If you want the entries to appear in a containing directory in the zip archive itself, then you should call the AddDirectory() overload that allows you to explicitly specify a directory path for use in the archive.

For ZipFile properties including Encryption, Password, SetCompression, ProvisionalAlternateEncoding, ExtractExistingFile, ZipErrorAction, and CompressionLevel, their respective values at the time of this call will be applied to each ZipEntry added.

See Also

AddDirectory(string, string)

Adds the contents of a filesystem directory to a Zip file archive, overriding the path to be used for entries in the archive.

public ZipEntry AddDirectory(string directoryName, string directoryPathInArchive)

Parameters

directoryName string

The name of the directory to add.

directoryPathInArchive string

Specifies a directory path to use to override any path in the DirectoryName. This path may, or may not, correspond to a real directory in the current filesystem. If the zip is later extracted, this is the path used for the extracted file or directory. Passing null (Nothing in VB) or the empty string ("") will insert the items at the root path within the archive.

Returns

ZipEntry

The ZipEntry added.

Examples

In this code, calling the ZipUp() method with a value of "c:\reports" for the directory parameter will result in a zip file structure in which all entries are contained in a toplevel "reports" directory.

public void ZipUp(string targetZip, string directory)
{
  using (var zip = new ZipFile())
  {
    zip.AddDirectory(directory, System.IO.Path.GetFileName(directory));
    zip.Save(targetZip);
  }
}

Remarks

The name of the directory may be a relative path or a fully-qualified path. The add operation is recursive, so that any files or subdirectories within the name directory are also added to the archive.

Top-level entries in the named directory will appear as top-level entries in the zip archive. Entries in subdirectories in the named directory will result in entries in subdirectories in the zip archive.

For ZipFile properties including Encryption, Password, SetCompression, ProvisionalAlternateEncoding, ExtractExistingFile, ZipErrorAction, and CompressionLevel, their respective values at the time of this call will be applied to each ZipEntry added.

See Also

AddDirectoryByName(string)

Creates a directory in the zip archive.

public ZipEntry AddDirectoryByName(string directoryNameInArchive)

Parameters

directoryNameInArchive string

The name of the directory to create in the archive.

Returns

ZipEntry

The ZipEntry added.

Remarks

Use this when you want to create a directory in the archive but there is no corresponding filesystem representation for that directory.

You will probably not need to do this in your code. One of the only times you will want to do this is if you want an empty directory in the zip archive. The reason: if you add a file to a zip archive that is stored within a multi-level directory, all of the directory tree is implicitly created in the zip archive.

AddEntry(ZipEntry)

Adds a ZipEntry to the zip file.

public void AddEntry(ZipEntry ze)

Parameters

ze ZipEntry

The ZipEntry to add.

Exceptions

InvalidOperationException

Thrown if the ze already belongs to a zip file.

AddEntry(string, OpenDelegate, CloseDelegate)

Add an entry, for which the application will provide a stream containing the entry data, on a just-in-time basis.

public ZipEntry AddEntry(string entryName, OpenDelegate opener, CloseDelegate closer)

Parameters

entryName string

the name of the entry to add

opener OpenDelegate

the delegate that will be invoked by ZipFile.Save() to get the readable stream for the given entry. ZipFile.Save() will call read on this stream to obtain the data for the entry. This data will then be compressed and written to the newly created zip file.

closer CloseDelegate

the delegate that will be invoked to close the stream. This may be null (Nothing in VB), in which case no call is makde to close the stream.

Returns

ZipEntry

the ZipEntry added

Examples

This example uses anonymous methods in C# to open and close the source stream for the content for a zip entry.

using(Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile())
{
    zip.AddEntry(zipEntryName,
                 (name) =>  File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite ),
                 (name, stream) =>  stream.Close()
                 );

    zip.Save(zipFileName);
}

This example uses delegates in VB.NET to open and close the the source stream for the content for a zip entry. VB 9.0 lacks support for "Sub" lambda expressions, and so the CloseDelegate must be an actual, named Sub.

Function MyStreamOpener(ByVal entryName As String) As Stream
    '' This simply opens a file.  You probably want to do somethinig
    '' more involved here: open a stream to read from a database,
    '' open a stream on an HTTP connection, and so on.
    Return File.OpenRead(entryName)
End Function

Sub MyStreamCloser(entryName As String, stream As Stream)
    stream.Close()
End Sub

Public Sub Run()
    Dim dirToZip As String = "fodder"
    Dim zipFileToCreate As String = "Archive.zip"
    Dim opener As OpenDelegate = AddressOf MyStreamOpener
    Dim closer As CloseDelegate = AddressOf MyStreamCloser
    Dim numFilestoAdd As Int32 = 4
    Using zip As ZipFile = New ZipFile
        Dim i As Integer
        For i = 0 To numFilesToAdd - 1
            zip.AddEntry(String.Format("content-{0:000}.txt"), opener, closer)
        Next i
        zip.Save(zipFileToCreate)
    End Using
End Sub

Remarks

In cases where the application wishes to open the stream that holds the content for the ZipEntry, on a just-in-time basis, the application can use this method. The application provides an opener delegate that will be called by the DotNetZip library to obtain a readable stream that can be read to get the bytes for the given entry. Typically, this delegate opens a stream. Optionally, the application can provide a closer delegate as well, which will be called by DotNetZip when all bytes have been read from the entry.

These delegates are called from within the scope of the call to ZipFile.Save().

For ZipFile properties including Encryption, Password, SetCompression, ProvisionalAlternateEncoding, ExtractExistingFile, ZipErrorAction, and CompressionLevel, their respective values at the time of this call will be applied to the ZipEntry added.

AddEntry(string, WriteDelegate)

Add a ZipEntry for which content is written directly by the application.

public ZipEntry AddEntry(string entryName, WriteDelegate writer)

Parameters

entryName string

the name of the entry to add

writer WriteDelegate

the delegate which will write the entry content

Returns

ZipEntry

the ZipEntry added

Examples

This example shows an application filling a DataSet, then saving the contents of that DataSet as XML, into a ZipEntry in a ZipFile, using an anonymous delegate in C#. The DataSet XML is never saved to a disk file.

var c1= new System.Data.SqlClient.SqlConnection(connstring1);
var da = new System.Data.SqlClient.SqlDataAdapter()
    {
        SelectCommand=  new System.Data.SqlClient.SqlCommand(strSelect, c1)
    };

DataSet ds1 = new DataSet();
da.Fill(ds1, "Invoices");

using(Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile())
{
    zip.AddEntry(zipEntryName, (name,stream) => ds1.WriteXml(stream) );
    zip.Save(zipFileName);
}

This example uses an anonymous method in C# as the WriteDelegate to provide the data for the ZipEntry. The example is a bit contrived - the AddFile() method is a simpler way to insert the contents of a file into an entry in a zip file. On the other hand, if there is some sort of processing or transformation of the file contents required before writing, the application could use the WriteDelegate to do it, in this way.

using (var input = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite ))
{
    using(Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile())
    {
        zip.AddEntry(zipEntryName, (name,output) =>
            {
                byte[] buffer = new byte[BufferSize];
                int n;
                while ((n = input.Read(buffer, 0, buffer.Length)) != 0)
                {
                    // could transform the data here...
                    output.Write(buffer, 0, n);
                    // could update a progress bar here
                }
            });

        zip.Save(zipFileName);
    }
}

This example uses a named delegate in VB to write data for the given ZipEntry (VB9 does not have anonymous delegates). The example here is a bit contrived - a simpler way to add the contents of a file to a ZipEntry is to simply use the appropriate AddFile() method. The key scenario for which the WriteDelegate makes sense is saving a DataSet, in XML format, to the zip file. The DataSet can write XML to a stream, and the WriteDelegate is the perfect place to write into the zip file. There may be other data structures that can write to a stream, but cannot be read as a stream. The WriteDelegate would be appropriate for those cases as well.

Private Sub WriteEntry (ByVal name As String, ByVal output As Stream)
    Using input As FileStream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
        Dim n As Integer = -1
        Dim buffer As Byte() = New Byte(BufferSize){}
        Do While n <> 0
            n = input.Read(buffer, 0, buffer.Length)
            output.Write(buffer, 0, n)
        Loop
    End Using
End Sub

Public Sub Run()
    Using zip = New ZipFile
        zip.AddEntry(zipEntryName, New WriteDelegate(AddressOf WriteEntry))
        zip.Save(zipFileName)
    End Using
End Sub

Remarks

When the application needs to write the zip entry data, use this method to add the ZipEntry. For example, in the case that the application wishes to write the XML representation of a DataSet into a ZipEntry, the application can use this method to do so.

For ZipFile properties including Encryption, Password, SetCompression, ProvisionalAlternateEncoding, ExtractExistingFile, ZipErrorAction, and CompressionLevel, their respective values at the time of this call will be applied to the ZipEntry added.

About progress events: When using the WriteDelegate, DotNetZip does not issue any SaveProgress events with EventType = Saving_EntryBytesRead. (This is because it is the application's code that runs in WriteDelegate - there's no way for DotNetZip to know when to issue a EntryBytesRead event.) Applications that want to update a progress bar or similar status indicator should do so from within the WriteDelegate itself. DotNetZip will issue the other SaveProgress events, including Saving_Started, Saving_BeforeWriteEntry, and Saving_AfterWriteEntry.

Note: When you use PKZip encryption, it's normally necessary to compute the CRC of the content to be encrypted, before compressing or encrypting it. Therefore, when using PKZip encryption with a WriteDelegate, the WriteDelegate CAN BE called twice: once to compute the CRC, and the second time to potentially compress and encrypt. Surprising, but true. This is because PKWARE specified that the encryption initialization data depends on the CRC. If this happens, for each call of the delegate, your application must stream the same entry data in its entirety. If your application writes different data during the second call, it will result in a corrupt zip file.

The double-read behavior happens with all types of entries, not only those that use WriteDelegate. It happens if you add an entry from a filesystem file, or using a string, or a stream, or an opener/closer pair. But in those cases, DotNetZip takes care of reading twice; in the case of the WriteDelegate, the application code gets invoked twice. Be aware.

As you can imagine, this can cause performance problems for large streams, and it can lead to correctness problems when you use a WriteDelegate. This is a pretty big pitfall. There are two ways to avoid it. First, and most preferred: don't use PKZIP encryption. If you use the WinZip AES encryption, this problem doesn't occur, because the encryption protocol doesn't require the CRC up front. Second: if you do choose to use PKZIP encryption, write out to a non-seekable stream (like standard output, or the Response.OutputStream in an ASP.NET application). In this case, DotNetZip will use an alternative encryption protocol that does not rely on the CRC of the content. This also implies setting bit 3 in the zip entry, which still presents problems for some zip tools.

In the future I may modify DotNetZip to *always* use bit 3 when PKZIP encryption is in use. This seems like a win overall, but there will be some work involved. If you feel strongly about it, visit the DotNetZip forums and vote up the Workitem tracking this issue.

AddEntry(string, byte[])

Add an entry into the zip archive using the given filename and directory path within the archive, and the given content for the file. No file is created in the filesystem.

public ZipEntry AddEntry(string entryName, byte[] byteContent)

Parameters

entryName string

The name, including any path, to use within the archive for the entry.

byteContent byte[]

The data to use for the entry.

Returns

ZipEntry

The ZipEntry added.

AddEntry(string, Stream)

Create an entry in the ZipFile using the given Stream as input. The entry will have the given filename.

public ZipEntry AddEntry(string entryName, Stream stream)

Parameters

entryName string

The name, including any path, which is shown in the zip file for the added entry.

stream Stream

The input stream from which to grab content for the file

Returns

ZipEntry

The ZipEntry added.

Examples

This example adds a single entry to a ZipFile via a Stream.

String zipToCreate = "Content.zip";
String fileNameInArchive = "Content-From-Stream.bin";
using (System.IO.Stream streamToRead = MyStreamOpener())
{
  using (ZipFile zip = new ZipFile())
  {
    ZipEntry entry= zip.AddEntry(fileNameInArchive, streamToRead);
    zip.AddFile("Readme.txt");
    zip.Save(zipToCreate);  // the stream is read implicitly here
  }
}
Dim zipToCreate As String = "Content.zip"
Dim fileNameInArchive As String = "Content-From-Stream.bin"
Using streamToRead as System.IO.Stream = MyStreamOpener()
  Using zip As ZipFile = New ZipFile()
    Dim entry as ZipEntry = zip.AddEntry(fileNameInArchive, streamToRead)
    zip.AddFile("Readme.txt")
    zip.Save(zipToCreate)  '' the stream is read implicitly, here
  End Using
End Using

Remarks

The application should provide an open, readable stream; in this case it will be read during the call to Save() or one of its overloads.

The passed stream will be read from its current position. If necessary, callers should set the position in the stream before calling AddEntry(). This might be appropriate when using this method with a MemoryStream, for example.

In cases where a large number of streams will be added to the ZipFile, the application may wish to avoid maintaining all of the streams open simultaneously. To handle this situation, the application should use the AddEntry(string, OpenDelegate, CloseDelegate) overload.

For ZipFile properties including Encryption, Password, SetCompression, ProvisionalAlternateEncoding, ExtractExistingFile, ZipErrorAction, and CompressionLevel, their respective values at the time of this call will be applied to the ZipEntry added.

See Also

AddEntry(string, string)

Adds a named entry into the zip archive, taking content for the entry from a string.

public ZipEntry AddEntry(string entryName, string content)

Parameters

entryName string

The name, including any path, to use for the entry within the archive.

content string

The content of the file, should it be extracted from the zip.

Returns

ZipEntry

The ZipEntry added.

Examples

This example shows how to add an entry to the zipfile, using a string as content for that entry.

string Content = "This string will be the content of the Readme.txt file in the zip archive.";
using (ZipFile zip1 = new ZipFile())
{
  zip1.AddFile("MyDocuments\\Resume.doc", "files");
  zip1.AddEntry("Readme.txt", Content);
  zip1.Comment = "This zip file was created at " + System.DateTime.Now.ToString("G");
  zip1.Save("Content.zip");
}
Public Sub Run()
  Dim Content As String = "This string will be the content of the Readme.txt file in the zip archive."
  Using zip1 As ZipFile = New ZipFile
    zip1.AddEntry("Readme.txt", Content)
    zip1.AddFile("MyDocuments\Resume.doc", "files")
    zip1.Comment = ("This zip file was created at " & DateTime.Now.ToString("G"))
    zip1.Save("Content.zip")
  End Using
End Sub

Remarks

Calling this method creates an entry using the given fileName and directory path within the archive. There is no need for a file by the given name to exist in the filesystem; the name is used within the zip archive only. The content for the entry is encoded using the default text encoding for the machine.

AddEntry(string, string, Encoding)

Adds a named entry into the zip archive, taking content for the entry from a string, and using the specified text encoding.

public ZipEntry AddEntry(string entryName, string content, Encoding encoding)

Parameters

entryName string

The name, including any path, to use within the archive for the entry.

content string

The content of the file, should it be extracted from the zip.

encoding Encoding

The text encoding to use when encoding the string. Be aware: This is distinct from the text encoding used to encode the fileName, as specified in ProvisionalAlternateEncoding.

Returns

ZipEntry

The ZipEntry added.

Remarks

Calling this method creates an entry using the given fileName and directory path within the archive. There is no need for a file by the given name to exist in the filesystem; the name is used within the zip archive only.

The content for the entry, a string value, is encoded using the given text encoding. A BOM (byte-order-mark) is emitted into the file, if the Encoding parameter is set for that.

Most Encoding classes support a constructor that accepts a boolean, indicating whether to emit a BOM or not. For example see UTF8Encoding(bool).

AddFile(string)

Adds a File to a Zip file archive.

public ZipEntry AddFile(string fileName)

Parameters

fileName string

The name of the file to add. It should refer to a file in the filesystem. The name of the file may be a relative path or a fully-qualified path.

Returns

ZipEntry

The ZipEntry corresponding to the File added.

Examples

In this example, three files are added to a Zip archive. The ReadMe.txt file will be placed in the root of the archive. The .png file will be placed in a folder within the zip called photos\personal. The pdf file will be included into a folder within the zip called Desktop.

try
{
  using (ZipFile zip = new ZipFile())
  {
    zip.AddFile("c:\\photos\\personal\\7440-N49th.png");
    zip.AddFile("c:\\Desktop\\2008-Regional-Sales-Report.pdf");
    zip.AddFile("ReadMe.txt");
zip.Save("Package.zip");

} } catch (System.Exception ex1) { System.Console.Error.WriteLine("exception: " + ex1); }

Try
     Using zip As ZipFile = New ZipFile
         zip.AddFile("c:\photos\personal\7440-N49th.png")
         zip.AddFile("c:\Desktop\2008-Regional-Sales-Report.pdf")
         zip.AddFile("ReadMe.txt")
         zip.Save("Package.zip")
     End Using
 Catch ex1 As Exception
     Console.Error.WriteLine("exception: {0}", ex1.ToString)
 End Try

Remarks

This call collects metadata for the named file in the filesystem, including the file attributes and the timestamp, and inserts that metadata into the resulting ZipEntry. Only when the application calls Save() on the ZipFile, does DotNetZip read the file from the filesystem and then write the content to the zip file archive.

This method will throw an exception if an entry with the same name already exists in the ZipFile.

For ZipFile properties including Encryption, Password, SetCompression, ProvisionalAlternateEncoding, ExtractExistingFile, ZipErrorAction, and CompressionLevel, their respective values at the time of this call will be applied to the ZipEntry added.

See Also

AddFile(string, string)

Adds a File to a Zip file archive, potentially overriding the path to be used within the zip archive.

public ZipEntry AddFile(string fileName, string directoryPathInArchive)

Parameters

fileName string

The name of the file to add. The name of the file may be a relative path or a fully-qualified path.

directoryPathInArchive string

Specifies a directory path to use to override any path in the fileName. This path may, or may not, correspond to a real directory in the current filesystem. If the files within the zip are later extracted, this is the path used for the extracted file. Passing null (Nothing in VB) will use the path on the fileName, if any. Passing the empty string ("") will insert the item at the root path within the archive.

Returns

ZipEntry

The ZipEntry corresponding to the file added.

Examples

In this example, three files are added to a Zip archive. The ReadMe.txt file will be placed in the root of the archive. The .png file will be placed in a folder within the zip called images. The pdf file will be included into a folder within the zip called files\docs, and will be encrypted with the given password.

try
{
  using (ZipFile zip = new ZipFile())
  {
    // the following entry will be inserted at the root in the archive.
    zip.AddFile("c:\\datafiles\\ReadMe.txt", "");
    // this image file will be inserted into the "images" directory in the archive.
    zip.AddFile("c:\\photos\\personal\\7440-N49th.png", "images");
    // the following will result in a password-protected file called
    // files\\docs\\2008-Regional-Sales-Report.pdf  in the archive.
    zip.Password = "EncryptMe!";
    zip.AddFile("c:\\Desktop\\2008-Regional-Sales-Report.pdf", "files\\docs");
    zip.Save("Archive.zip");
  }
}
catch (System.Exception ex1)
{
  System.Console.Error.WriteLine("exception: {0}", ex1);
}
Try
    Using zip As ZipFile = New ZipFile
        ' the following entry will be inserted at the root in the archive.
        zip.AddFile("c:\datafiles\ReadMe.txt", "")
        ' this image file will be inserted into the "images" directory in the archive.
        zip.AddFile("c:\photos\personal\7440-N49th.png", "images")
        ' the following will result in a password-protected file called
        ' files\\docs\\2008-Regional-Sales-Report.pdf  in the archive.
        zip.Password = "EncryptMe!"
        zip.AddFile("c:\Desktop\2008-Regional-Sales-Report.pdf", "files\documents")
        zip.Save("Archive.zip")
    End Using
Catch ex1 As Exception
    Console.Error.WriteLine("exception: {0}", ex1)
End Try

Remarks

The file added by this call to the ZipFile is not written to the zip file archive until the application calls Save() on the ZipFile.

This method will throw an exception if an entry with the same name already exists in the ZipFile.

This version of the method allows the caller to explicitly specify the directory path to be used in the archive.

For ZipFile properties including Encryption, Password, SetCompression, ProvisionalAlternateEncoding, ExtractExistingFile, ZipErrorAction, and CompressionLevel, their respective values at the time of this call will be applied to the ZipEntry added.

See Also

AddFiles(IEnumerable<string>)

This method adds a set of files to the ZipFile.

public void AddFiles(IEnumerable<string> fileNames)

Parameters

fileNames IEnumerable<string>

The collection of names of the files to add. Each string should refer to a file in the filesystem. The name of the file may be a relative path or a fully-qualified path.

Examples

This example shows how to create a zip file, and add a few files into it.

String ZipFileToCreate = "archive1.zip";
String DirectoryToZip = "c:\\reports";
using (ZipFile zip = new ZipFile())
{
  // Store all files found in the top level directory, into the zip archive.
  String[] filenames = System.IO.Directory.GetFiles(DirectoryToZip);
  zip.AddFiles(filenames);
  zip.Save(ZipFileToCreate);
}
Dim ZipFileToCreate As String = "archive1.zip"
Dim DirectoryToZip As String = "c:\reports"
Using zip As ZipFile = New ZipFile
    ' Store all files found in the top level directory, into the zip archive.
    Dim filenames As String() = System.IO.Directory.GetFiles(DirectoryToZip)
    zip.AddFiles(filenames)
    zip.Save(ZipFileToCreate)
End Using

Remarks

Use this method to add a set of files to the zip archive, in one call. For example, a list of files received from System.IO.Directory.GetFiles() can be added to a zip archive in one call.

For ZipFile properties including Encryption, Password, SetCompression, ProvisionalAlternateEncoding, ExtractExistingFile, ZipErrorAction, and CompressionLevel, their respective values at the time of this call will be applied to each ZipEntry added.

See Also

AddFiles(IEnumerable<string>, bool, string)

Adds a set of files to the ZipFile, using the specified directory path in the archive, and preserving the full directory structure in the filenames.

public void AddFiles(IEnumerable<string> fileNames, bool preserveDirHierarchy, string directoryPathInArchive)

Parameters

fileNames IEnumerable<string>

The names of the files to add. Each string should refer to a file in the filesystem. The name of the file may be a relative path or a fully-qualified path.

preserveDirHierarchy bool

whether the entries in the zip archive will reflect the directory hierarchy that is present in the various filenames. For example, if fileNames includes two paths, \Animalia\Chordata\Mammalia\Info.txt and \Plantae\Magnoliophyta\Dicotyledon\Info.txt, then calling this method with preserveDirHierarchy = false will result in an exception because of a duplicate entry name, while calling this method with preserveDirHierarchy = true will result in the full direcory paths being included in the entries added to the ZipFile.

directoryPathInArchive string

Specifies a directory path to use as a prefix for each entry name. This path may, or may not, correspond to a real directory in the current filesystem. If the files within the zip are later extracted, this is the path used for the extracted file. Passing null (Nothing in VB) will use the path on each of the fileNames, if any. Passing the empty string ("") will insert the item at the root path within the archive.

Remarks

Think of the directoryPathInArchive as a "root" or base directory used in the archive for the files that get added. when preserveDirHierarchy is true, the hierarchy of files found in the filesystem will be placed, with the hierarchy intact, starting at that root in the archive. When preserveDirHierarchy is false, the path hierarchy of files is flattned, and the flattened set of files gets placed in the root within the archive as specified in directoryPathInArchive.

For ZipFile properties including Encryption, Password, SetCompression, ProvisionalAlternateEncoding, ExtractExistingFile, ZipErrorAction, and CompressionLevel, their respective values at the time of this call will be applied to each ZipEntry added.

See Also

AddFiles(IEnumerable<string>, string)

Adds a set of files to the ZipFile, using the specified directory path in the archive.

public void AddFiles(IEnumerable<string> fileNames, string directoryPathInArchive)

Parameters

fileNames IEnumerable<string>

The names of the files to add. Each string should refer to a file in the filesystem. The name of the file may be a relative path or a fully-qualified path.

directoryPathInArchive string

Specifies a directory path to use to override any path in the file name. Th is path may, or may not, correspond to a real directory in the current filesystem. If the files within the zip are later extracted, this is the path used for the extracted file. Passing null (Nothing in VB) will use the path on each of the fileNames, if any. Passing the empty string ("") will insert the item at the root path within the archive.

Remarks

Any directory structure that may be present in the filenames contained in the list is "flattened" in the archive. Each file in the list is added to the archive in the specified top-level directory.

For ZipFile properties including Encryption, Password, SetCompression, ProvisionalAlternateEncoding, ExtractExistingFile, ZipErrorAction, and CompressionLevel, their respective values at the time of this call will be applied to each ZipEntry added.

See Also

AddItem(string)

Adds an item, either a file or a directory, to a zip file archive.

public ZipEntry AddItem(string fileOrDirectoryName)

Parameters

fileOrDirectoryName string

the name of the file or directory to add.

Returns

ZipEntry

The ZipEntry added.

Remarks

This method is handy if you are adding things to zip archive and don't want to bother distinguishing between directories or files. Any files are added as single entries. A directory added through this method is added recursively: all files and subdirectories contained within the directory are added to the ZipFile.

The name of the item may be a relative path or a fully-qualified path. Remember, the items contained in ZipFile instance get written to the disk only when you call Save() or a similar save method.

The directory name used for the file within the archive is the same as the directory name (potentially a relative path) specified in the fileOrDirectoryName.

For ZipFile properties including Encryption, Password, SetCompression, ProvisionalAlternateEncoding, ExtractExistingFile, ZipErrorAction, and CompressionLevel, their respective values at the time of this call will be applied to the ZipEntry added.

See Also

AddItem(string, string)

Adds an item, either a file or a directory, to a zip file archive, explicitly specifying the directory path to be used in the archive.

public ZipEntry AddItem(string fileOrDirectoryName, string directoryPathInArchive)

Parameters

fileOrDirectoryName string

the name of the file or directory to add.

directoryPathInArchive string

The name of the directory path to use within the zip archive. This path need not refer to an extant directory in the current filesystem. If the files within the zip are later extracted, this is the path used for the extracted file. Passing null (Nothing in VB) will use the path on the fileOrDirectoryName. Passing the empty string ("") will insert the item at the root path within the archive.

Returns

ZipEntry

The ZipEntry added.

Examples

This example shows how to zip up a set of files into a flat hierarchy, regardless of where in the filesystem the files originated. The resulting zip archive will contain a toplevel directory named "flat", which itself will contain files Readme.txt, MyProposal.docx, and Image1.jpg. A subdirectory under "flat" called SupportFiles will contain all the files in the "c:\SupportFiles" directory on disk.

String[] itemnames= {
  "c:\\fixedContent\\Readme.txt",
  "MyProposal.docx",
  "c:\\SupportFiles",  // a directory
  "images\\Image1.jpg"
};

try
{
  using (ZipFile zip = new ZipFile())
  {
    for (int i = 1; i < itemnames.Length; i++)
    {
      // will add Files or Dirs, recurses and flattens subdirectories
      zip.AddItem(itemnames[i],"flat");
    }
    zip.Save(ZipToCreate);
  }
}
catch (System.Exception ex1)
{
  System.Console.Error.WriteLine("exception: {0}", ex1);
}
Dim itemnames As String() = _
  New String() { "c:\fixedContent\Readme.txt", _
                 "MyProposal.docx", _
                 "SupportFiles", _
                 "images\Image1.jpg" }
Try
    Using zip As New ZipFile
        Dim i As Integer
        For i = 1 To itemnames.Length - 1
            ' will add Files or Dirs, recursing and flattening subdirectories.
            zip.AddItem(itemnames(i), "flat")
        Next i
        zip.Save(ZipToCreate)
    End Using
Catch ex1 As Exception
    Console.Error.WriteLine("exception: {0}", ex1.ToString())
End Try

Remarks

If adding a directory, the add is recursive on all files and subdirectories contained within it.

The name of the item may be a relative path or a fully-qualified path. The item added by this call to the ZipFile is not read from the disk nor written to the zip file archive until the application calls Save() on the ZipFile.

This version of the method allows the caller to explicitly specify the directory path to be used in the archive, which would override the "natural" path of the filesystem file.

Encryption will be used on the file data if the Password has been set on the ZipFile object, prior to calling this method.

For ZipFile properties including Encryption, Password, SetCompression, ProvisionalAlternateEncoding, ExtractExistingFile, ZipErrorAction, and CompressionLevel, their respective values at the time of this call will be applied to the ZipEntry added.

Exceptions

FileNotFoundException

Thrown if the file or directory passed in does not exist.

See Also

AddSelectedFiles(string)

Adds to the ZipFile a set of files from the current working directory on disk, that conform to the specified criteria.

public void AddSelectedFiles(string selectionCriteria)

Parameters

selectionCriteria string

The criteria for file selection

Examples

This example zips up all *.csv files in the current working directory.

using (ZipFile zip = new ZipFile())
{
    // To just match on filename wildcards,
    // use the shorthand form of the selectionCriteria string.
    zip.AddSelectedFiles("*.csv");
    zip.Save(PathToZipArchive);
}
Using zip As ZipFile = New ZipFile()
    zip.AddSelectedFiles("*.csv")
    zip.Save(PathToZipArchive)
End Using

Remarks

This method selects files from the the current working directory matching the specified criteria, and adds them to the ZipFile.

Specify the criteria in statements of 3 elements: a noun, an operator, and a value. Consider the string "name != *.doc" . The noun is "name". The operator is "!=", implying "Not Equal". The value is "*.doc". That criterion, in English, says "all files with a name that does not end in the .doc extension."

Supported nouns include "name" (or "filename") for the filename; "atime", "mtime", and "ctime" for last access time, last modfied time, and created time of the file, respectively; "attributes" (or "attrs") for the file attributes; "size" (or "length") for the file length (uncompressed), and "type" for the type of object, either a file or a directory. The "attributes", "name" and "type" nouns both support = and != as operators. The "size", "atime", "mtime", and "ctime" nouns support = and !=, and >, >=, <, <= as well. The times are taken to be expressed in local time.

Specify values for the file attributes as a string with one or more of the characters H,R,text,A,I,L in any order, implying file attributes of Hidden, ReadOnly, System, Archive, NotContextIndexed, and ReparsePoint (symbolic link) respectively.

To specify a time, use YYYY-MM-DD-HH:mm:ss or YYYY/MM/DD-HH:mm:ss as the format. If you omit the HH:mm:ss portion, it is assumed to be 00:00:00 (midnight).

The value for a size criterion is expressed in integer quantities of bytes, kilobytes (use k or kb after the number), megabytes (m or mb), or gigabytes (g or gb).

The value for a name is a pattern to match against the filename, potentially including wildcards. The pattern follows CMD.exe glob rules: * implies one or more of any character, while ? implies one character. If the name pattern contains any slashes, it is matched to the entire filename, including the path; otherwise, it is matched against only the filename without the path. This means a pattern of "*\*.*" matches all files one directory level deep, while a pattern of "*.*" matches all files in all directories.

To specify a name pattern that includes spaces, use single quotes around the pattern. A pattern of "'* *.*'" will match all files that have spaces in the filename. The full criteria string for that would be "name = '* *.*'" .

The value for a type criterion is either F (implying a file) or D (implying a directory).

Some examples:

criteriaFiles retrieved
name != *.xls any file with an extension that is not .xls
name = *.mp3 any file with a .mp3 extension.
*.mp3(same as above) any file with a .mp3 extension.
attributes = A all files whose attributes include the Archive bit.
attributes != H all files whose attributes do not include the Hidden bit.
mtime > 2009-01-01all files with a last modified time after January 1st, 2009.
size > 2gball files whose uncompressed size is greater than 2gb.
type = Dall directories in the filesystem.

You can combine criteria with the conjunctions AND or OR. Using a string like "name = *.txt AND size >= 100k" for the selectionCriteria retrieves entries whose names end in .txt, and whose uncompressed size is greater than or equal to 100 kilobytes.

For more complex combinations of criteria, you can use parenthesis to group clauses in the boolean logic. Without parenthesis, the precedence of the criterion atoms is determined by order of appearance. Unlike the C# language, the AND conjunction does not take precendence over the logical OR. This is important only in strings that contain 3 or more criterion atoms. In other words, "name = *.txt and size > 1000 or attributes = H" implies "((name = *.txt AND size > 1000) OR attributes = H)" while "attributes = H OR name = *.txt and size > 1000" evaluates to "((attributes = H OR name = *.txt) AND size > 1000)". When in doubt, use parenthesis.

Using time properties requires some extra care. If you want to retrieve all entries that were last updated on 2009 February 14, specify a time range like so:"mtime >= 2009-02-14 AND mtime < 2009-02-15". Read this to say: all files updated after 12:00am on February 14th, until 12:00am on February 15th. You can use the same bracketing approach to specify any time period - a year, a month, a week, and so on.

The syntax allows one special case: if you provide a string with no spaces, it is treated as a pattern to match for the filename. Therefore a string like "*.xls" will be equivalent to specifying "name = *.xls".

There is no logic in this method that insures that the file inclusion criteria are internally consistent. For example, it's possible to specify criteria that says the file must have a size of less than 100 bytes, as well as a size that is greater than 1000 bytes. Obviously no file will ever satisfy such criteria, but this method does not detect such logical inconsistencies. The caller is responsible for insuring the criteria are sensible.

Using this method, the file selection does not recurse into subdirectories, and the full path of the selected files is included in the entries added into the zip archive. If you don't like these behaviors, see the other overloads of this method.

AddSelectedFiles(string, bool)

Adds to the ZipFile a set of files from the disk that conform to the specified criteria, optionally recursing into subdirectories.

public void AddSelectedFiles(string selectionCriteria, bool recurseDirectories)

Parameters

selectionCriteria string

The criteria for file selection

recurseDirectories bool

If true, the file selection will recurse into subdirectories.

Examples

This example zips up all *.xml files in the current working directory, or any subdirectory, that are larger than 1mb.

using (ZipFile zip = new ZipFile())
{
    // Use a compound expression in the selectionCriteria string.
    zip.AddSelectedFiles("name = *.xml  and  size > 1024kb", true);
    zip.Save(PathToZipArchive);
}
Using zip As ZipFile = New ZipFile()
    ' Use a compound expression in the selectionCriteria string.
    zip.AddSelectedFiles("name = *.xml  and  size > 1024kb", true)
    zip.Save(PathToZipArchive)
End Using

Remarks

This method selects files from the the current working directory matching the specified criteria, and adds them to the ZipFile. If recurseDirectories is true, files are also selected from subdirectories, and the directory structure in the filesystem is reproduced in the zip archive, rooted at the current working directory.

Using this method, the full path of the selected files is included in the entries added into the zip archive. If you don't want this behavior, use one of the overloads of this method that allows the specification of a directoryInArchive.

For details on the syntax for the selectionCriteria parameter, see AddSelectedFiles(string).

AddSelectedFiles(string, string)

Adds to the ZipFile a set of files from a specified directory in the filesystem, that conform to the specified criteria.

public void AddSelectedFiles(string selectionCriteria, string directoryOnDisk)

Parameters

selectionCriteria string

The criteria for file selection

directoryOnDisk string

The name of the directory on the disk from which to select files.

Examples

This example zips up all *.xml files larger than 1mb in the directory given by "d:\rawdata".

using (ZipFile zip = new ZipFile())
{
    // Use a compound expression in the selectionCriteria string.
    zip.AddSelectedFiles("name = *.xml  and  size > 1024kb", "d:\\rawdata");
    zip.Save(PathToZipArchive);
}
Using zip As ZipFile = New ZipFile()
    ' Use a compound expression in the selectionCriteria string.
    zip.AddSelectedFiles("name = *.xml  and  size > 1024kb", "d:\rawdata)
    zip.Save(PathToZipArchive)
End Using

Remarks

This method selects files that conform to the specified criteria, from the the specified directory on disk, and adds them to the ZipFile. The search does not recurse into subdirectores.

Using this method, the full filesystem path of the files on disk is reproduced on the entries added to the zip file. If you don't want this behavior, use one of the other overloads of this method.

For details on the syntax for the selectionCriteria parameter, see AddSelectedFiles(string).

AddSelectedFiles(string, string, bool)

Adds to the ZipFile a set of files from the specified directory on disk, that conform to the specified criteria.

public void AddSelectedFiles(string selectionCriteria, string directoryOnDisk, bool recurseDirectories)

Parameters

selectionCriteria string

The criteria for file selection

directoryOnDisk string

The filesystem path from which to select files.

recurseDirectories bool

If true, the file selection will recurse into subdirectories.

Examples

This example zips up all *.csv files in the "files" directory, or any subdirectory, that have been saved since 2009 February 14th.

using (ZipFile zip = new ZipFile())
{
    // Use a compound expression in the selectionCriteria string.
    zip.AddSelectedFiles("name = *.csv  and  mtime > 2009-02-14", "files", true);
    zip.Save(PathToZipArchive);
}
Using zip As ZipFile = New ZipFile()
    ' Use a compound expression in the selectionCriteria string.
    zip.AddSelectedFiles("name = *.csv  and  mtime > 2009-02-14", "files", true)
    zip.Save(PathToZipArchive)
End Using

This example zips up all files in the current working directory, and all its child directories, except those in the excludethis subdirectory.

Using Zip As ZipFile = New ZipFile(zipfile)
  Zip.AddSelectedFfiles("name != 'excludethis\*.*'", datapath, True)
  Zip.Save()
End Using

Remarks

This method selects files from the the specified disk directory matching the specified selection criteria, and adds them to the ZipFile. If recurseDirectories is true, files are also selected from subdirectories.

The full directory structure in the filesystem is reproduced on the entries added to the zip archive. If you don't want this behavior, use one of the overloads of this method that allows the specification of a directoryInArchive.

For details on the syntax for the selectionCriteria parameter, see AddSelectedFiles(string).

AddSelectedFiles(string, string, string)

Adds to the ZipFile a selection of files from the specified directory on disk, that conform to the specified criteria, and using a specified root path for entries added to the zip archive.

public void AddSelectedFiles(string selectionCriteria, string directoryOnDisk, string directoryPathInArchive)

Parameters

selectionCriteria string

The criteria for selection of files to add to the ZipFile.

directoryOnDisk string

The path to the directory in the filesystem from which to select files.

directoryPathInArchive string

Specifies a directory path to use to in place of the directoryOnDisk. This path may, or may not, correspond to a real directory in the current filesystem. If the files within the zip are later extracted, this is the path used for the extracted file. Passing null (nothing in VB) will use the path on the file name, if any; in other words it would use directoryOnDisk, plus any subdirectory. Passing the empty string ("") will insert the item at the root path within the archive.

Examples

This example zips up all *.psd files in the "photos" directory that have been saved since 2009 February 14th, and puts them all in a zip file, using the directory name of "content" in the zip archive itself. When the zip archive is unzipped, the folder containing the .psd files will be named "content".

using (ZipFile zip = new ZipFile())
{
    // Use a compound expression in the selectionCriteria string.
    zip.AddSelectedFiles("name = *.psd  and  mtime > 2009-02-14", "photos", "content");
    zip.Save(PathToZipArchive);
}
Using zip As ZipFile = New ZipFile
    zip.AddSelectedFiles("name = *.psd  and  mtime > 2009-02-14", "photos", "content")
    zip.Save(PathToZipArchive)
End Using

Remarks

This method selects files from the specified disk directory matching the specified selection criteria, and adds those files to the ZipFile, using the specified directory path in the archive. The search does not recurse into subdirectories. For details on the syntax for the selectionCriteria parameter, see AddSelectedFiles(string).

AddSelectedFiles(string, string, string, bool)

Adds to the ZipFile a selection of files from the specified directory on disk, that conform to the specified criteria, optionally recursing through subdirectories, and using a specified root path for entries added to the zip archive.

public void AddSelectedFiles(string selectionCriteria, string directoryOnDisk, string directoryPathInArchive, bool recurseDirectories)

Parameters

selectionCriteria string

The criteria for selection of files to add to the ZipFile.

directoryOnDisk string

The path to the directory in the filesystem from which to select files.

directoryPathInArchive string

Specifies a directory path to use to in place of the directoryOnDisk. This path may, or may not, correspond to a real directory in the current filesystem. If the files within the zip are later extracted, this is the path used for the extracted file. Passing null (nothing in VB) will use the path on the file name, if any; in other words it would use directoryOnDisk, plus any subdirectory. Passing the empty string ("") will insert the item at the root path within the archive.

recurseDirectories bool

If true, the method also scans subdirectories for files matching the criteria.

Examples

This example zips up all files that are NOT *.pst files, in the current working directory and any subdirectories.

using (ZipFile zip = new ZipFile())
{
    zip.AddSelectedFiles("name != *.pst", SourceDirectory, "backup", true);
    zip.Save(PathToZipArchive);
}
Using zip As ZipFile = New ZipFile
    zip.AddSelectedFiles("name != *.pst", SourceDirectory, "backup", true)
    zip.Save(PathToZipArchive)
End Using

Remarks

This method selects files from the specified disk directory that match the specified selection criteria, and adds those files to the ZipFile, using the specified directory path in the archive. If recurseDirectories is true, files are also selected from subdirectories, and the directory structure in the filesystem is reproduced in the zip archive, rooted at the directory specified by directoryOnDisk. For details on the syntax for the selectionCriteria parameter, see AddSelectedFiles(string).

CheckZip(string)

Checks a zip file to see if its directory is consistent.

public static bool CheckZip(string zipFileName)

Parameters

zipFileName string

The filename to of the zip file to check.

Returns

bool

true if the named zip file checks OK. Otherwise, false.

Remarks

In cases of data error, the directory within a zip file can get out of synch with the entries in the zip file. This method checks the given zip file and returns true if this has occurred.

This method may take a long time to run for large zip files.

This method is not supported in the Reduced version of DotNetZip.

Developers using COM can use the ComHelper.CheckZip(String) method.

See Also

CheckZip(string, bool, TextWriter)

Checks a zip file to see if its directory is consistent, and optionally fixes the directory if necessary.

public static bool CheckZip(string zipFileName, bool fixIfNecessary, TextWriter writer)

Parameters

zipFileName string

The filename to of the zip file to check.

fixIfNecessary bool

If true, the method will fix the zip file if necessary.

writer TextWriter

a TextWriter in which messages generated while checking will be written.

Returns

bool

true if the named zip is OK; false if the file needs to be fixed.

Remarks

In cases of data error, the directory within a zip file can get out of synch with the entries in the zip file. This method checks the given zip file, and returns true if this has occurred. It also optionally fixes the zipfile, saving the fixed copy in Name_Fixed.zip.

This method may take a long time to run for large zip files. It will take even longer if the file actually needs to be fixed, and if fixIfNecessary is true.

This method is not supported in the Reduced version of DotNetZip.

See Also

CheckZipPassword(string, string)

Verify the password on a zip file.

public static bool CheckZipPassword(string zipFileName, string password)

Parameters

zipFileName string

The filename to of the zip file to fix.

password string

The password to check.

Returns

bool

a bool indicating whether the password matches.

Remarks

Keep in mind that passwords in zipfiles are applied to zip entries, not to the entire zip file. So testing a zipfile for a particular password doesn't work in the general case. On the other hand, it's often the case that a single password will be used on all entries in a zip file. This method works for that case.

There is no way to check a password without doing the decryption. So this code decrypts and extracts the given zipfile into Null

ContainsEntry(string)

Returns true if an entry by the given name exists in the ZipFile.

public bool ContainsEntry(string name)

Parameters

name string

the name of the entry to find

Returns

bool

true if an entry with the given name exists; otherwise false.

Dispose()

Closes the read and write streams associated to the ZipFile, if necessary.

public void Dispose()

Examples

This example extracts an entry selected by name, from the Zip file to the Console.

using (ZipFile zip = ZipFile.Read(zipfile))
{
  foreach (ZipEntry e in zip)
  {
    if (WantThisEntry(e.FileName))
      zip.Extract(e.FileName, Console.OpenStandardOutput());
  }
} // Dispose() is called implicitly here.
Using zip As ZipFile = ZipFile.Read(zipfile)
    Dim e As ZipEntry
    For Each e In zip
      If WantThisEntry(e.FileName) Then
          zip.Extract(e.FileName, Console.OpenStandardOutput())
      End If
    Next
End Using ' Dispose is implicity called here

Remarks

The Dispose() method is generally employed implicitly, via a using(..) {..} statement. (Using...End Using in VB) If you do not employ a using statement, insure that your application calls Dispose() explicitly. For example, in a Powershell application, or an application that uses the COM interop interface, you must call Dispose() explicitly.

Dispose(bool)

Disposes any managed resources, if the flag is set, then marks the instance disposed. This method is typically not called explicitly from application code.

protected virtual void Dispose(bool disposeManagedResources)

Parameters

disposeManagedResources bool

indicates whether the method should dispose streams or not.

Remarks

Applications should call the no-arg Dispose method.

ExtractAll(string)

Extracts all of the items in the zip archive, to the specified path in the filesystem. The path can be relative or fully-qualified.

public void ExtractAll(string path)

Parameters

path string

The path to which the contents of the zipfile will be extracted. The path can be relative or fully-qualified.

Examples

This example extracts all the entries in a zip archive file, to the specified target directory. The extraction will overwrite any existing files silently.

String TargetDirectory= "unpack";
using(ZipFile zip= ZipFile.Read(ZipFileToExtract))
{
    zip.ExtractExistingFile= ExtractExistingFileAction.OverwriteSilently;
    zip.ExtractAll(TargetDirectory);
}
Dim TargetDirectory As String = "unpack"
Using zip As ZipFile = ZipFile.Read(ZipFileToExtract)
    zip.ExtractExistingFile= ExtractExistingFileAction.OverwriteSilently
    zip.ExtractAll(TargetDirectory)
End Using

Remarks

This method will extract all entries in the ZipFile to the specified path.

If an extraction of a file from the zip archive would overwrite an existing file in the filesystem, the action taken is dictated by the ExtractExistingFile property, which overrides any setting you may have made on individual ZipEntry instances. By default, if you have not set that property on the ZipFile instance, the entry will not be extracted, the existing file will not be overwritten and an exception will be thrown. To change this, set the property, or use the ExtractAll(string, ExtractExistingFileAction) overload that allows you to specify an ExtractExistingFileAction parameter.

The action to take when an extract would overwrite an existing file applies to all entries. If you want to set this on a per-entry basis, then you must use one of the ZipEntry.Extract methods.

This method will send verbose output messages to the StatusMessageTextWriter, if it is set on the ZipFile instance.

You may wish to take advantage of the ExtractProgress event.

About timestamps: When extracting a file entry from a zip archive, the extracted file gets the last modified time of the entry as stored in the archive. The archive may also store extended file timestamp information, including last accessed and created times. If these are present in the ZipEntry, then the extracted file will also get these times.

A Directory entry is somewhat different. It will get the times as described for a file entry, but, if there are file entries in the zip archive that, when extracted, appear in the just-created directory, then when those file entries are extracted, the last modified and last accessed times of the directory will change, as a side effect. The result is that after an extraction of a directory and a number of files within the directory, the last modified and last accessed timestamps on the directory will reflect the time that the last file was extracted into the directory, rather than the time stored in the zip archive for the directory.

To compensate, when extracting an archive with ExtractAll, DotNetZip will extract all the file and directory entries as described above, but it will then make a second pass on the directories, and reset the times on the directories to reflect what is stored in the zip archive.

This compensation is performed only within the context of an ExtractAll. If you call ZipEntry.Extract on a directory entry, the timestamps on directory in the filesystem will reflect the times stored in the zip. If you then call ZipEntry.Extract on a file entry, which is extracted into the directory, the timestamps on the directory will be updated to the current time.

See Also

ExtractAll(string, ExtractExistingFileAction)

Extracts all of the items in the zip archive, to the specified path in the filesystem, using the specified behavior when extraction would overwrite an existing file.

public void ExtractAll(string path, ExtractExistingFileAction extractExistingFile)

Parameters

path string

The path to which the contents of the zipfile will be extracted. The path can be relative or fully-qualified.

extractExistingFile ExtractExistingFileAction

The action to take if extraction would overwrite an existing file.

Examples

This example extracts all the entries in a zip archive file, to the specified target directory. It does not overwrite any existing files.

String TargetDirectory= "c:\\unpack";
using(ZipFile zip= ZipFile.Read(ZipFileToExtract))
{
  zip.ExtractAll(TargetDirectory, ExtractExistingFileAction.DontOverwrite);
}
Dim TargetDirectory As String = "c:\unpack"
Using zip As ZipFile = ZipFile.Read(ZipFileToExtract)
    zip.ExtractAll(TargetDirectory, ExtractExistingFileAction.DontOverwrite)
End Using

Remarks

This method will extract all entries in the ZipFile to the specified path. For an extraction that would overwrite an existing file, the behavior is dictated by extractExistingFile, which overrides any setting you may have made on individual ZipEntry instances.

The action to take when an extract would overwrite an existing file applies to all entries. If you want to set this on a per-entry basis, then you must use Extract(string, ExtractExistingFileAction) or one of the similar methods.

Calling this method is equivalent to setting the ExtractExistingFile property and then calling ExtractAll(string).

This method will send verbose output messages to the StatusMessageTextWriter, if it is set on the ZipFile instance.

See Also

ExtractSelectedEntries(string)

Selects and Extracts a set of Entries from the ZipFile.

public void ExtractSelectedEntries(string selectionCriteria)

Parameters

selectionCriteria string

the selection criteria for entries to extract.

Examples

This example shows how extract all XML files modified after 15 January 2009.

using (ZipFile zip = ZipFile.Read(zipArchiveName))
{
  zip.ExtractSelectedEntries("name = *.xml  and  mtime > 2009-01-15");
}

Remarks

The entries are extracted into the current working directory.

If any of the files to be extracted already exist, then the action taken is as specified in the ExtractExistingFile property on the corresponding ZipEntry instance. By default, the action taken in this case is to throw an exception.

For information on the syntax of the selectionCriteria string, see AddSelectedFiles(string).

See Also

ExtractSelectedEntries(string, ExtractExistingFileAction)

Selects and Extracts a set of Entries from the ZipFile.

public void ExtractSelectedEntries(string selectionCriteria, ExtractExistingFileAction extractExistingFile)

Parameters

selectionCriteria string

the selection criteria for entries to extract.

extractExistingFile ExtractExistingFileAction

The action to take if extraction would overwrite an existing file.

Examples

This example shows how extract all XML files modified after 15 January 2009, overwriting any existing files.

using (ZipFile zip = ZipFile.Read(zipArchiveName))
{
  zip.ExtractSelectedEntries("name = *.xml  and  mtime > 2009-01-15",
                             ExtractExistingFileAction.OverwriteSilently);
}

Remarks

The entries are extracted into the current working directory. When extraction would would overwrite an existing filesystem file, the action taken is as specified in the extractExistingFile parameter.

For information on the syntax of the string describing the entry selection criteria, see AddSelectedFiles(string).

ExtractSelectedEntries(string, string)

Selects and Extracts a set of Entries from the ZipFile.

public void ExtractSelectedEntries(string selectionCriteria, string directoryPathInArchive)

Parameters

selectionCriteria string

the selection criteria for entries to extract.

directoryPathInArchive string

the directory in the archive from which to select entries. If null, then all directories in the archive are used.

Examples

This example shows how extract all XML files modified after 15 January 2009, and writes them to the "unpack" directory.

using (ZipFile zip = ZipFile.Read(zipArchiveName))
{
  zip.ExtractSelectedEntries("name = *.xml  and  mtime > 2009-01-15","unpack");
}

Remarks

The entries are selected from the specified directory within the archive, and then extracted into the current working directory.

If any of the files to be extracted already exist, then the action taken is as specified in the ExtractExistingFile property on the corresponding ZipEntry instance. By default, the action taken in this case is to throw an exception.

For information on the syntax of the string describing the entry selection criteria, see AddSelectedFiles(string).

See Also

ExtractSelectedEntries(string, string, string)

Selects and Extracts a set of Entries from the ZipFile.

public void ExtractSelectedEntries(string selectionCriteria, string directoryInArchive, string extractDirectory)

Parameters

selectionCriteria string

the selection criteria for entries to extract.

directoryInArchive string

the directory in the archive from which to select entries. If null, then all directories in the archive are used.

extractDirectory string

the directory on the disk into which to extract. It will be created if it does not exist.

Remarks

The entries are extracted into the specified directory. If any of the files to be extracted already exist, an exception will be thrown.

For information on the syntax of the string describing the entry selection criteria, see AddSelectedFiles(string).

ExtractSelectedEntries(string, string, string, ExtractExistingFileAction)

Selects and Extracts a set of Entries from the ZipFile.

public void ExtractSelectedEntries(string selectionCriteria, string directoryPathInArchive, string extractDirectory, ExtractExistingFileAction extractExistingFile)

Parameters

selectionCriteria string

the selection criteria for entries to extract.

directoryPathInArchive string

The directory in the archive from which to select entries. If null, then all directories in the archive are used.

extractDirectory string

The directory on the disk into which to extract. It will be created if it does not exist.

extractExistingFile ExtractExistingFileAction

The action to take if extraction would overwrite an existing file.

Examples

This example shows how extract all files with an XML extension or with a size larger than 100,000 bytes, and puts them in the unpack directory. For any files that already exist in that destination directory, they will not be overwritten.

using (ZipFile zip = ZipFile.Read(zipArchiveName))
{
  zip.ExtractSelectedEntries("name = *.xml  or  size > 100000",
                             null,
                             "unpack",
                             ExtractExistingFileAction.DontOverwrite);
}

Remarks

The entries are extracted into the specified directory. When extraction would would overwrite an existing filesystem file, the action taken is as specified in the extractExistingFile parameter.

For information on the syntax of the string describing the entry selection criteria, see AddSelectedFiles(string).

FixZipDirectory(string)

Rewrite the directory within a zipfile.

public static void FixZipDirectory(string zipFileName)

Parameters

zipFileName string

The filename to of the zip file to fix.

Remarks

In cases of data error, the directory in a zip file can get out of synch with the entries in the zip file. This method attempts to fix the zip file if this has occurred.

This can take a long time for large zip files.

This won't work if the zip file uses a non-standard code page - neither IBM437 nor UTF-8.

This method is not supported in the Reduced or Compact Framework versions of DotNetZip.

Developers using COM can use the ComHelper.FixZipDirectory(String) method.

See Also

GetEnumerator()

Generic IEnumerator support, for use of a ZipFile in an enumeration.

public IEnumerator<ZipEntry> GetEnumerator()

Returns

IEnumerator<ZipEntry>

A generic enumerator suitable for use within a foreach loop.

Examples

This example reads a zipfile of a given name, then enumerates the entries in that zip file, and displays the information about each entry on the Console.

using (ZipFile zip = ZipFile.Read(zipfile))
{
  bool header = true;
  foreach (ZipEntry e in zip)
  {
    if (header)
    {
       System.Console.WriteLine("Zipfile: {0}", zip.Name);
       System.Console.WriteLine("Version Needed: 0x{0:X2}", e.VersionNeeded);
       System.Console.WriteLine("BitField: 0x{0:X2}", e.BitField);
       System.Console.WriteLine("Compression Method: 0x{0:X2}", e.CompressionMethod);
       System.Console.WriteLine("\n{1,-22} {2,-6} {3,4}   {4,-8}  {0}",
                    "Filename", "Modified", "Size", "Ratio", "Packed");
       System.Console.WriteLine(new System.String('-', 72));
       header = false;
    }

    System.Console.WriteLine("{1,-22} {2,-6} {3,4:F0}%   {4,-8}  {0}",
                e.FileName,
                e.LastModified.ToString("yyyy-MM-dd HH:mm:ss"),
                e.UncompressedSize,
                e.CompressionRatio,
                e.CompressedSize);

    e.Extract();
  }
}
Dim ZipFileToExtract As String = "c:\foo.zip"
Using zip As ZipFile = ZipFile.Read(ZipFileToExtract)
    Dim header As Boolean = True
    Dim e As ZipEntry
    For Each e In zip
        If header Then
            Console.WriteLine("Zipfile: {0}", zip.Name)
            Console.WriteLine("Version Needed: 0x{0:X2}", e.VersionNeeded)
            Console.WriteLine("BitField: 0x{0:X2}", e.BitField)
            Console.WriteLine("Compression Method: 0x{0:X2}", e.CompressionMethod)
            Console.WriteLine(ChrW(10) & "{1,-22} {2,-6} {3,4}   {4,-8}  {0}", _
              "Filename", "Modified", "Size", "Ratio", "Packed" )
            Console.WriteLine(New String("-"c, 72))
            header = False
        End If
        Console.WriteLine("{1,-22} {2,-6} {3,4:F0}%   {4,-8}  {0}", _
          e.FileName, _
          e.LastModified.ToString("yyyy-MM-dd HH:mm:ss"), _
          e.UncompressedSize, _
          e.CompressionRatio, _
          e.CompressedSize )
        e.Extract
    Next
End Using

Remarks

You probably do not want to call GetEnumerator explicitly. Instead it is implicitly called when you use a foreach loop in C#, or a For Each loop in VB.NET.

GetNewEnum()

An IEnumerator, for use of a ZipFile in a foreach construct.

public IEnumerator GetNewEnum()

Returns

IEnumerator

The IEnumerator over the entries in the ZipFile.

Remarks

This method is included for COM support. An application generally does not call this method directly. It is called implicitly by COM clients when enumerating the entries in the ZipFile instance. In VBScript, this is done with a For Each statement. In Javascript, this is done with new Enumerator(zipfile).

Initialize(string)

Initialize a ZipFile instance by reading in a zip file.

public void Initialize(string fileName)

Parameters

fileName string

the name of the existing zip file to read in.

Remarks

This method is primarily useful from COM Automation environments, when reading or extracting zip files. In COM, it is not possible to invoke parameterized constructors for a class. A COM Automation application can update a zip file by using the default (no argument) constructor, then calling Initialize() to read the contents of an on-disk zip archive into the ZipFile instance.

.NET applications are encouraged to use the ZipFile.Read() methods for better clarity.

IsZipFile(Stream, bool)

Checks a stream to see if it contains a valid zip archive.

public static bool IsZipFile(Stream stream, bool testExtract)

Parameters

stream Stream

The stream to check.

testExtract bool

true if the caller wants to extract each entry.

Returns

bool

true if the stream contains a valid zip archive.

Remarks

This method reads the zip archive contained in the specified stream, verifying the ZIP metadata as it reads. If testExtract is true, this method also extracts each entry in the archive, dumping all the bits into Null.

If everything succeeds, then the method returns true. If anything fails - for example if an incorrect signature or CRC is found, indicating a corrupt file, the the method returns false. This method also returns false for a file that does not exist.

If testExtract is true, this method reads in the content for each entry, expands it, and checks CRCs. This provides an additional check beyond verifying the zip header data.

If testExtract is true, and if any of the zip entries are protected with a password, this method will return false. If you want to verify a ZipFile that has entries which are protected with a password, you will need to do that manually.

See Also

IsZipFile(string)

Checks the given file to see if it appears to be a valid zip file.

public static bool IsZipFile(string fileName)

Parameters

fileName string

The file to check.

Returns

bool

true if the file appears to be a zip file.

Remarks

Calling this method is equivalent to calling IsZipFile(string, bool) with the testExtract parameter set to false.

IsZipFile(string, bool)

Checks a file to see if it is a valid zip file.

public static bool IsZipFile(string fileName, bool testExtract)

Parameters

fileName string

The zip file to check.

testExtract bool

true if the caller wants to extract each entry.

Returns

bool

true if the file contains a valid zip file.

Remarks

This method opens the specified zip file, reads in the zip archive, verifying the ZIP metadata as it reads.

If everything succeeds, then the method returns true. If anything fails - for example if an incorrect signature or CRC is found, indicating a corrupt file, the the method returns false. This method also returns false for a file that does not exist.

If testExtract is true, as part of its check, this method reads in the content for each entry, expands it, and checks CRCs. This provides an additional check beyond verifying the zip header and directory data.

If testExtract is true, and if any of the zip entries are protected with a password, this method will return false. If you want to verify a ZipFile that has entries which are protected with a password, you will need to do that manually.

Read(Stream)

Reads a zip archive from a stream.

public static ZipFile Read(Stream zipStream)

Parameters

zipStream Stream

the stream containing the zip data.

Returns

ZipFile

The ZipFile instance read from the stream

Examples

This example shows how to Read zip content from a stream, and extract one entry into a different stream. In this example, the filename "NameOfEntryInArchive.doc", refers only to the name of the entry within the zip archive. A file by that name is not created in the filesystem. The I/O is done strictly with the given streams.

using (ZipFile zip = ZipFile.Read(InputStream))
{
   zip.Extract("NameOfEntryInArchive.doc", OutputStream);
}
Using zip as ZipFile = ZipFile.Read(InputStream)
   zip.Extract("NameOfEntryInArchive.doc", OutputStream)
End Using

Remarks

When reading from a file, it's probably easier to just use ZipFile.Read(String, ReadOptions). This overload is useful when when the zip archive content is available from an already-open stream. The stream must be open and readable and seekable when calling this method. The stream is left open when the reading is completed.

Using this overload, the stream is read using the default System.Text.Encoding, which is the IBM437 codepage. If you want to specify the encoding to use when reading the zipfile content, see ZipFile.Read(Stream, ReadOptions). This

Reading of zip content begins at the current position in the stream. This means if you have a stream that concatenates regular data and zip data, if you position the open, readable stream at the start of the zip data, you will be able to read the zip archive using this constructor, or any of the ZipFile constructors that accept a Stream as input. Some examples of where this might be useful: the zip content is concatenated at the end of a regular EXE file, as some self-extracting archives do. (Note: SFX files produced by DotNetZip do not work this way; they can be read as normal ZIP files). Another example might be a stream being read from a database, where the zip content is embedded within an aggregate stream of data.

Read(Stream, ReadOptions)

Reads a zip file archive from the given stream using the specified options.

public static ZipFile Read(Stream zipStream, ReadOptions options)

Parameters

zipStream Stream

the stream containing the zip data.

options ReadOptions

The set of options to use when reading the zip file.

Returns

ZipFile

The ZipFile instance read from the stream.

Remarks

When reading from a file, it's probably easier to just use ZipFile.Read(String, ReadOptions). This overload is useful when when the zip archive content is available from an already-open stream. The stream must be open and readable and seekable when calling this method. The stream is left open when the reading is completed.

Reading of zip content begins at the current position in the stream. This means if you have a stream that concatenates regular data and zip data, if you position the open, readable stream at the start of the zip data, you will be able to read the zip archive using this constructor, or any of the ZipFile constructors that accept a Stream as input. Some examples of where this might be useful: the zip content is concatenated at the end of a regular EXE file, as some self-extracting archives do. (Note: SFX files produced by DotNetZip do not work this way; they can be read as normal ZIP files). Another example might be a stream being read from a database, where the zip content is embedded within an aggregate stream of data.

Exceptions

Exception

Thrown if the zip archive cannot be read.

See Also

Read(string)

Reads a zip file archive and returns the instance.

public static ZipFile Read(string fileName)

Parameters

fileName string

The name of the zip archive to open. This can be a fully-qualified or relative pathname.

Returns

ZipFile

The instance read from the zip archive.

Remarks

The stream is read using the default System.Text.Encoding, which is the IBM437 codepage.

Exceptions

Exception

Thrown if the ZipFile cannot be read. The implementation of this method relies on System.IO.File.OpenRead, which can throw a variety of exceptions, including specific exceptions if a file is not found, an unauthorized access exception, exceptions for poorly formatted filenames, and so on.

See Also

Read(string, ReadOptions)

Reads a zip file archive from the named filesystem file using the specified options.

public static ZipFile Read(string fileName, ReadOptions options)

Parameters

fileName string

The name of the zip archive to open. This can be a fully-qualified or relative pathname.

options ReadOptions

The set of options to use when reading the zip file.

Returns

ZipFile

The ZipFile instance read from the zip archive.

Examples

This example shows how to read a zip file using the Big-5 Chinese code page (950), and extract each entry in the zip file, while sending status messages out to the Console.

For this code to work as intended, the zipfile must have been created using the big5 code page (CP950). This is typical, for example, when using WinRar on a machine with CP950 set as the default code page. In that case, the names of entries within the Zip archive will be stored in that code page, and reading the zip archive must be done using that code page. If the application did not use the correct code page in ZipFile.Read(), then names of entries within the zip archive would not be correctly retrieved.

string zipToExtract = "MyArchive.zip";
string extractDirectory = "extract";
var options = new ReadOptions
{
  StatusMessageWriter = System.Console.Out,
  Encoding = System.Text.Encoding.GetEncoding(950)
};
using (ZipFile zip = ZipFile.Read(zipToExtract, options))
{
  foreach (ZipEntry e in zip)
  {
     e.Extract(extractDirectory);
  }
}
Dim zipToExtract as String = "MyArchive.zip"
Dim extractDirectory as String = "extract"
Dim options as New ReadOptions
options.Encoding = System.Text.Encoding.GetEncoding(950)
options.StatusMessageWriter = System.Console.Out
Using zip As ZipFile = ZipFile.Read(zipToExtract, options)
    Dim e As ZipEntry
    For Each e In zip
     e.Extract(extractDirectory)
    Next
End Using

This example shows how to read a zip file using the default code page, to remove entries that have a modified date before a given threshold, sending status messages out to a StringWriter.

var options = new ReadOptions
{
  StatusMessageWriter = new System.IO.StringWriter()
};
using (ZipFile zip =  ZipFile.Read("PackedDocuments.zip", options))
{
  var Threshold = new DateTime(2007,7,4);
  // We cannot remove the entry from the list, within the context of
  // an enumeration of said list.
  // So we add the doomed entry to a list to be removed later.
  // pass 1: mark the entries for removal
  var MarkedEntries = new System.Collections.Generic.List<ZipEntry>();
  foreach (ZipEntry e in zip)
  {
    if (e.LastModified < Threshold)
      MarkedEntries.Add(e);
  }
  // pass 2: actually remove the entry.
  foreach (ZipEntry zombie in MarkedEntries)
     zip.RemoveEntry(zombie);
  zip.Comment = "This archive has been updated.";
  zip.Save();
}
// can now use contents of sw, eg store in an audit log
Dim options as New ReadOptions
options.StatusMessageWriter = New System.IO.StringWriter
Using zip As ZipFile = ZipFile.Read("PackedDocuments.zip", options)
    Dim Threshold As New DateTime(2007, 7, 4)
    ' We cannot remove the entry from the list, within the context of
    ' an enumeration of said list.
    ' So we add the doomed entry to a list to be removed later.
    ' pass 1: mark the entries for removal
    Dim MarkedEntries As New System.Collections.Generic.List(Of ZipEntry)
    Dim e As ZipEntry
    For Each e In zip
        If (e.LastModified < Threshold) Then
            MarkedEntries.Add(e)
        End If
    Next
    ' pass 2: actually remove the entry.
    Dim zombie As ZipEntry
    For Each zombie In MarkedEntries
        zip.RemoveEntry(zombie)
    Next
    zip.Comment = "This archive has been updated."
    zip.Save
End Using
' can now use contents of sw, eg store in an audit log

Remarks

This version of the Read() method allows the caller to pass in a TextWriter an Encoding, via an instance of the ReadOptions class. The ZipFile is read in using the specified encoding for entries where UTF-8 encoding is not explicitly specified.

Exceptions

Exception

Thrown if the zipfile cannot be read. The implementation of this method relies on System.IO.File.OpenRead, which can throw a variety of exceptions, including specific exceptions if a file is not found, an unauthorized access exception, exceptions for poorly formatted filenames, and so on.

See Also

RemoveEntries(ICollection<ZipEntry>)

This method removes a collection of entries from the ZipFile.

public void RemoveEntries(ICollection<ZipEntry> entriesToRemove)

Parameters

entriesToRemove ICollection<ZipEntry>

A collection of ZipEntry instances from this zip file to be removed. For example, you can pass in an array of ZipEntry instances; or you can call SelectEntries(), and then add or remove entries from that ICollection<ZipEntry> (ICollection(Of ZipEntry) in VB), and pass that ICollection to this method.

See Also

RemoveEntries(ICollection<string>)

This method removes a collection of entries from the ZipFile, by name.

public void RemoveEntries(ICollection<string> entriesToRemove)

Parameters

entriesToRemove ICollection<string>

A collection of strings that refer to names of entries to be removed from the ZipFile. For example, you can pass in an array or a List of Strings that provide the names of entries to be removed.

See Also

RemoveEntry(ZipEntry)

Removes the given ZipEntry from the zip archive.

public void RemoveEntry(ZipEntry entry)

Parameters

entry ZipEntry

The ZipEntry to remove from the zip.

Examples

In this example, all entries in the zip archive dating from before December 31st, 2007, are removed from the archive. This is actually much easier if you use the RemoveSelectedEntries method. But I needed an example for RemoveEntry, so here it is.

String ZipFileToRead = "ArchiveToModify.zip";
System.DateTime Threshold = new System.DateTime(2007,12,31);
using (ZipFile zip = ZipFile.Read(ZipFileToRead))
{
  var EntriesToRemove = new System.Collections.Generic.List<ZipEntry>();
  foreach (ZipEntry e in zip)
  {
    if (e.LastModified < Threshold)
    {
      // We cannot remove the entry from the list, within the context of
      // an enumeration of said list.
      // So we add the doomed entry to a list to be removed later.
      EntriesToRemove.Add(e);
    }
  }

  // actually remove the doomed entries.
  foreach (ZipEntry zombie in EntriesToRemove)
    zip.RemoveEntry(zombie);

  zip.Comment= String.Format("This zip archive was updated at {0}.",
                             System.DateTime.Now.ToString("G"));

  // save with a different name
  zip.Save("Archive-Updated.zip");
}
Dim ZipFileToRead As String = "ArchiveToModify.zip"
Dim Threshold As New DateTime(2007, 12, 31)
Using zip As ZipFile = ZipFile.Read(ZipFileToRead)
    Dim EntriesToRemove As New System.Collections.Generic.List(Of ZipEntry)
    Dim e As ZipEntry
    For Each e In zip
        If (e.LastModified < Threshold) Then
            ' We cannot remove the entry from the list, within the context of
            ' an enumeration of said list.
            ' So we add the doomed entry to a list to be removed later.
            EntriesToRemove.Add(e)
        End If
    Next

    ' actually remove the doomed entries.
    Dim zombie As ZipEntry
    For Each zombie In EntriesToRemove
        zip.RemoveEntry(zombie)
    Next
    zip.Comment = String.Format("This zip archive was updated at {0}.", DateTime.Now.ToString("G"))
    'save as a different name
    zip.Save("Archive-Updated.zip")
End Using

Remarks

After calling RemoveEntry, the application must call Save to make the changes permanent.

Exceptions

ArgumentException

Thrown if the specified ZipEntry does not exist in the ZipFile.

See Also

RemoveEntry(string)

Removes the ZipEntry with the given filename from the zip archive.

public void RemoveEntry(string fileName)

Parameters

fileName string

The name of the file, including any directory path, to remove from the zip. The filename match is not case-sensitive by default; you can use the CaseSensitiveRetrieval property to change this behavior. The pathname can use forward-slashes or backward slashes.

Examples

This example shows one way to remove an entry with a given filename from an existing zip archive.

String zipFileToRead= "PackedDocuments.zip";
string candidate = "DatedMaterial.xps";
using (ZipFile zip = ZipFile.Read(zipFileToRead))
{
  if (zip.EntryFilenames.Contains(candidate))
  {
    zip.RemoveEntry(candidate);
    zip.Comment= String.Format("The file '{0}' has been removed from this archive.",
                               Candidate);
    zip.Save();
  }
}
Dim zipFileToRead As String = "PackedDocuments.zip"
Dim candidate As String = "DatedMaterial.xps"
Using zip As ZipFile = ZipFile.Read(zipFileToRead)
    If zip.EntryFilenames.Contains(candidate) Then
        zip.RemoveEntry(candidate)
        zip.Comment = String.Format("The file '{0}' has been removed from this archive.", Candidate)
        zip.Save
    End If
End Using

Remarks

After calling RemoveEntry, the application must call Save to make the changes permanent.

Exceptions

InvalidOperationException

Thrown if the ZipFile is not updatable.

ArgumentException

Thrown if a ZipEntry with the specified filename does not exist in the ZipFile.

RemoveSelectedEntries(string)

Remove entries from the zipfile by specified criteria.

public int RemoveSelectedEntries(string selectionCriteria)

Parameters

selectionCriteria string

the string that specifies which entries to select

Returns

int

the number of entries removed

Examples

This example removes all entries in a zip file that were modified prior to January 1st, 2008.

using (ZipFile zip1 = ZipFile.Read(ZipFileName))
{
    // remove all entries from prior to Jan 1, 2008
    zip1.RemoveEntries("mtime < 2008-01-01");
    // don't forget to save the archive!
    zip1.Save();
}
Using zip As ZipFile = ZipFile.Read(ZipFileName)
    ' remove all entries from prior to Jan 1, 2008
    zip1.RemoveEntries("mtime < 2008-01-01")
    ' do not forget to save the archive!
    zip1.Save
End Using

Remarks

This method allows callers to remove the collection of entries from the zipfile that fit the specified criteria. The criteria are described in a string format, and can include patterns for the filename; constraints on the size of the entry; constraints on the last modified, created, or last accessed time for the file described by the entry; or the attributes of the entry.

For details on the syntax for the selectionCriteria parameter, see AddSelectedFiles(string).

This method is intended for use with a ZipFile that has been read from storage. When creating a new ZipFile, this method will work only after the ZipArchive has been Saved to the disk (the ZipFile class subsequently and implicitly reads the Zip archive from storage.) Calling SelectEntries on a ZipFile that has not yet been saved will deliver undefined results.

Exceptions

Exception

Thrown if selectionCriteria has an invalid syntax.

RemoveSelectedEntries(string, string)

Remove entries from the zipfile by specified criteria, and within the specified path in the archive.

public int RemoveSelectedEntries(string selectionCriteria, string directoryPathInArchive)

Parameters

selectionCriteria string

the string that specifies which entries to select

directoryPathInArchive string

the directory in the archive from which to select entries. If null, then all directories in the archive are used.

Returns

int

the number of entries removed

Examples

using (ZipFile zip1 = ZipFile.Read(ZipFileName))
{
    // remove all entries from prior to Jan 1, 2008
    zip1.RemoveEntries("mtime < 2008-01-01", "documents");
    // a call to ZipFile.Save will make the modifications permanent
    zip1.Save();
}
Using zip As ZipFile = ZipFile.Read(ZipFileName)
    ' remove all entries from prior to Jan 1, 2008
    zip1.RemoveEntries("mtime < 2008-01-01", "documents")
    ' a call to ZipFile.Save will make the modifications permanent
    zip1.Save
End Using

Remarks

This method allows callers to remove the collection of entries from the zipfile that fit the specified criteria. The criteria are described in a string format, and can include patterns for the filename; constraints on the size of the entry; constraints on the last modified, created, or last accessed time for the file described by the entry; or the attributes of the entry.

For details on the syntax for the selectionCriteria parameter, see AddSelectedFiles(string).

This method is intended for use with a ZipFile that has been read from storage. When creating a new ZipFile, this method will work only after the ZipArchive has been Saved to the disk (the ZipFile class subsequently and implicitly reads the Zip archive from storage.) Calling SelectEntries on a ZipFile that has not yet been saved will deliver undefined results.

Exceptions

Exception

Thrown if selectionCriteria has an invalid syntax.

Save()

Saves the Zip archive to argument file, specified by the Name property of the ZipFile.

public void Save()

Remarks

The ZipFile instance is written to storage, typically argument zip file in argument filesystem, only when the caller calls Save. In the typical case, the Save operation writes the zip content to argument temporary file, and then renames the temporary file to the desired name. If necessary, this method will delete argument pre-existing file before the rename.

The Name property is specified either explicitly, or implicitly using one of the parameterized ZipFile constructors. For COM Automation clients, the Name property must be set explicitly, because COM Automation clients cannot call parameterized constructors.

When using argument filesystem file for the Zip output, it is possible to call Save multiple times on the ZipFile instance. With each call the zip content is re-written to the same output file.

Data for entries that have been added to the ZipFile instance is written to the output when the Save method is called. This means that the input streams for those entries must be available at the time the application calls Save. If, for example, the application adds entries with AddEntry using argument dynamically-allocated MemoryStream, the memory stream must not have been disposed before the call to Save. See the InputStream property for more discussion of the availability requirements of the input stream for an entry, and an approach for providing just-in-time stream lifecycle management.

Exceptions

BadStateException

Thrown if you haven't specified argument location or stream for saving the zip, either in the constructor or by setting the Name property, or if you try to save argument regular zip archive to argument filename with argument .exe extension.

OverflowException

Thrown if MaxOutputSegmentSize or MaxOutputSegmentSize64 is non-zero, and the number of segments that would be generated for the spanned zip file during the save operation exceeds 99. If this happens, you need to increase the segment size.

See Also

Save(Stream)

Save the zip archive to the specified stream.

public void Save(Stream outputStream)

Parameters

outputStream Stream

The System.IO.Stream to write to. It must be writable. If you created the ZipFile instance by calling ZipFile.Read(), this stream must not be the same stream you passed to ZipFile.Read().

Examples

This example saves the zipfile content into argument MemoryStream, and then gets the array of bytes from that MemoryStream.

using (var zip = new Ionic.Zip.ZipFile())
{
    zip.CompressionLevel= CompressionLevel.BestCompression;
    zip.Password = "VerySecret.";
    zip.Encryption = EncryptionAlgorithm.WinZipAes128;
    zip.AddFile(sourceFileName);
    MemoryStream output = new MemoryStream();
    zip.Save(output);

    byte[] zipbytes = output.ToArray();
}

This example shows argument pitfall you should avoid. DO NOT read from argument stream, then try to save to the same stream. DO NOT DO THIS:

using (var fs = new FileStream(filename, FileMode.Open))
{
  using (var zip = Ionic.Zip.ZipFile.Read(inputStream))
  {
    zip.AddEntry("Name1.txt", "this is the content");
    zip.Save(inputStream);  // NO NO NO!!
  }
}

Better like this:

using (var zip = Ionic.Zip.ZipFile.Read(filename))
{
    zip.AddEntry("Name1.txt", "this is the content");
    zip.Save();  // YES!
}

Remarks

The ZipFile instance is written to storage - typically argument zip file in argument filesystem, but using this overload, the storage can be anything accessible via argument writable stream - only when the caller calls Save.

Use this method to save the zip content to argument stream directly. argument common scenario is an ASP.NET application that dynamically generates argument zip file and allows the browser to download it. The application can call Save(Response.OutputStream) to write argument zipfile directly to the output stream, without creating argument zip file on the disk on the ASP.NET server.

Be careful when saving argument file to argument non-seekable stream, including Response.OutputStream. When DotNetZip writes to argument non-seekable stream, the zip archive is formatted in such argument way that may not be compatible with all zip tools on all platforms. It's argument perfectly legal and compliant zip file, but some people have reported problems opening files produced this way using the Mac OS archive utility.

Save(string)

Save the file to argument new zipfile, with the given name.

public void Save(string fileName)

Parameters

fileName string

The name of the zip archive to save to. Existing files will be overwritten with great prejudice.

Examples

This example shows how to create and Save argument zip file.

using (ZipFile zip = new ZipFile())
{
  zip.AddDirectory(@"c:\reports\January");
  zip.Save("January.zip");
}
Using zip As New ZipFile()
  zip.AddDirectory("c:\reports\January")
  zip.Save("January.zip")
End Using

This example shows how to update argument zip file.

using (ZipFile zip = ZipFile.Read("ExistingArchive.zip"))
{
  zip.AddFile("NewData.csv");
  zip.Save("UpdatedArchive.zip");
}
Using zip As ZipFile = ZipFile.Read("ExistingArchive.zip")
  zip.AddFile("NewData.csv")
  zip.Save("UpdatedArchive.zip")
End Using

Remarks

This method allows the application to explicitly specify the name of the zip file when saving. Use this when creating argument new zip file, or when updating argument zip archive.

An application can also save argument zip archive in several places by calling this method multiple times in succession, with different filenames.

The ZipFile instance is written to storage, typically argument zip file in argument filesystem, only when the caller calls Save. The Save operation writes the zip content to argument temporary file, and then renames the temporary file to the desired name. If necessary, this method will delete argument pre-existing file before the rename.

Exceptions

ArgumentException

Thrown if you specify argument directory for the filename.

SelectEntries(string)

Retrieve entries from the zipfile by specified criteria.

public ICollection<ZipEntry> SelectEntries(string selectionCriteria)

Parameters

selectionCriteria string

the string that specifies which entries to select

Returns

ICollection<ZipEntry>

a collection of ZipEntry objects that conform to the inclusion spec

Examples

This example selects all the PhotoShop files from within an archive, and extracts them to the current working directory.

using (ZipFile zip1 = ZipFile.Read(ZipFileName))
{
    var PhotoShopFiles = zip1.SelectEntries("*.psd");
    foreach (ZipEntry psd in PhotoShopFiles)
    {
        psd.Extract();
    }
}
Using zip1 As ZipFile = ZipFile.Read(ZipFileName)
    Dim PhotoShopFiles as ICollection(Of ZipEntry)
    PhotoShopFiles = zip1.SelectEntries("*.psd")
    Dim psd As ZipEntry
    For Each psd In PhotoShopFiles
        psd.Extract
    Next
End Using

Remarks

This method allows callers to retrieve the collection of entries from the zipfile that fit the specified criteria. The criteria are described in a string format, and can include patterns for the filename; constraints on the size of the entry; constraints on the last modified, created, or last accessed time for the file described by the entry; or the attributes of the entry.

For details on the syntax for the selectionCriteria parameter, see AddSelectedFiles(string).

This method is intended for use with a ZipFile that has been read from storage. When creating a new ZipFile, this method will work only after the ZipArchive has been Saved to the disk (the ZipFile class subsequently and implicitly reads the Zip archive from storage.) Calling SelectEntries on a ZipFile that has not yet been saved will deliver undefined results.

Exceptions

Exception

Thrown if selectionCriteria has an invalid syntax.

SelectEntries(string, string)

Retrieve entries from the zipfile by specified criteria.

public ICollection<ZipEntry> SelectEntries(string selectionCriteria, string directoryPathInArchive)

Parameters

selectionCriteria string

the string that specifies which entries to select

directoryPathInArchive string

the directory in the archive from which to select entries. If null, then all directories in the archive are used.

Returns

ICollection<ZipEntry>

a collection of ZipEntry objects that conform to the inclusion spec

Examples

using (ZipFile zip1 = ZipFile.Read(ZipFileName))
{
    var UpdatedPhotoShopFiles = zip1.SelectEntries("*.psd", "UpdatedFiles");
    foreach (ZipEntry e in UpdatedPhotoShopFiles)
    {
        // prompt for extract here
        if (WantExtract(e.FileName))
            e.Extract();
    }
}
Using zip1 As ZipFile = ZipFile.Read(ZipFileName)
    Dim UpdatedPhotoShopFiles As ICollection(Of ZipEntry) = zip1.SelectEntries("*.psd", "UpdatedFiles")
    Dim e As ZipEntry
    For Each e In UpdatedPhotoShopFiles
        ' prompt for extract here
        If Me.WantExtract(e.FileName) Then
            e.Extract
        End If
    Next
End Using

Remarks

This method allows callers to retrieve the collection of entries from the zipfile that fit the specified criteria. The criteria are described in a string format, and can include patterns for the filename; constraints on the size of the entry; constraints on the last modified, created, or last accessed time for the file described by the entry; or the attributes of the entry.

For details on the syntax for the selectionCriteria parameter, see AddSelectedFiles(string).

This method is intended for use with a ZipFile that has been read from storage. When creating a new ZipFile, this method will work only after the ZipArchive has been Saved to the disk (the ZipFile class subsequently and implicitly reads the Zip archive from storage.) Calling SelectEntries on a ZipFile that has not yet been saved will deliver undefined results.

Exceptions

Exception

Thrown if selectionCriteria has an invalid syntax.

ToString()

Provides a string representation of the instance.

public override string ToString()

Returns

string

a string representation of the instance.

UpdateDirectory(string)

Add or update a directory in a zip archive.

public ZipEntry UpdateDirectory(string directoryName)

Parameters

directoryName string

The path to the directory to be added to the zip archive, or updated in the zip archive.

Returns

ZipEntry

The ZipEntry corresponding to the Directory that was added or updated.

Remarks

If the specified directory does not exist in the archive, then this method is equivalent to calling AddDirectory(). If the specified directory already exists in the archive, then this method updates any existing entries, and adds any new entries. Any entries that are in the zip archive but not in the specified directory, are left alone. In other words, the contents of the zip file will be a union of the previous contents and the new files.

See Also

UpdateDirectory(string, string)

Add or update a directory in the zip archive at the specified root directory in the archive.

public ZipEntry UpdateDirectory(string directoryName, string directoryPathInArchive)

Parameters

directoryName string

The path to the directory to be added to the zip archive, or updated in the zip archive.

directoryPathInArchive string

Specifies a directory path to use to override any path in the directoryName. This path may, or may not, correspond to a real directory in the current filesystem. If the files within the zip are later extracted, this is the path used for the extracted file. Passing null (Nothing in VB) will use the path on the directoryName, if any. Passing the empty string ("") will insert the item at the root path within the archive.

Returns

ZipEntry

The ZipEntry corresponding to the Directory that was added or updated.

Remarks

If the specified directory does not exist in the archive, then this method is equivalent to calling AddDirectory(). If the specified directory already exists in the archive, then this method updates any existing entries, and adds any new entries. Any entries that are in the zip archive but not in the specified directory, are left alone. In other words, the contents of the zip file will be a union of the previous contents and the new files.

See Also

UpdateEntry(string, OpenDelegate, CloseDelegate)

Updates the given entry in the ZipFile, using the given delegates to open and close the stream that provides the content for the ZipEntry.

public ZipEntry UpdateEntry(string entryName, OpenDelegate opener, CloseDelegate closer)

Parameters

entryName string

The name, including any path, to use within the archive for the entry.

opener OpenDelegate

the delegate that will be invoked to open the stream

closer CloseDelegate

the delegate that will be invoked to close the stream

Returns

ZipEntry

The ZipEntry added or updated.

Remarks

Calling this method is equivalent to removing the ZipEntry for the given file name and directory path, if it exists, and then calling AddEntry(string, OpenDelegate, CloseDelegate). See the documentation for that method for further explanation.

UpdateEntry(string, WriteDelegate)

Updates the given entry in the ZipFile, using the given delegate as the source for content for the ZipEntry.

public ZipEntry UpdateEntry(string entryName, WriteDelegate writer)

Parameters

entryName string

The name, including any path, to use within the archive for the entry.

writer WriteDelegate

the delegate which will write the entry content.

Returns

ZipEntry

The ZipEntry added.

Remarks

Calling this method is equivalent to removing the ZipEntry for the given file name and directory path, if it exists, and then calling AddEntry(string, WriteDelegate). See the documentation for that method for further explanation.

UpdateEntry(string, byte[])

Updates the given entry in the ZipFile, using the given byte array as content for the entry.

public ZipEntry UpdateEntry(string entryName, byte[] byteContent)

Parameters

entryName string

The name, including any path, to use within the archive for the entry.

byteContent byte[]

The content to use for the ZipEntry.

Returns

ZipEntry

The ZipEntry added.

Remarks

Calling this method is equivalent to removing the ZipEntry for the given filename and directory path, if it exists, and then calling AddEntry(string, byte[]). See the documentation for that method for further explanation.

UpdateEntry(string, Stream)

Updates the given entry in the ZipFile, using the given stream as input, and the given filename and given directory Path.

public ZipEntry UpdateEntry(string entryName, Stream stream)

Parameters

entryName string

The name, including any path, to use within the archive for the entry.

stream Stream

The input stream from which to read file data.

Returns

ZipEntry

The ZipEntry added.

Remarks

Calling the method is equivalent to calling RemoveEntry() if an entry by the same name already exists, and then calling AddEntry() with the given fileName and stream.

The stream must be open and readable during the call to ZipFile.Save. You can dispense the stream on a just-in-time basis using the InputStream property. Check the documentation of that property for more information.

For ZipFile properties including Encryption, Password, SetCompression, ProvisionalAlternateEncoding, ExtractExistingFile, ZipErrorAction, and CompressionLevel, their respective values at the time of this call will be applied to the ZipEntry added.

See Also

UpdateEntry(string, string)

Updates the given entry in the ZipFile, using the given string as content for the ZipEntry.

public ZipEntry UpdateEntry(string entryName, string content)

Parameters

entryName string

The name, including any path, to use within the archive for the entry.

content string

The content of the file, should it be extracted from the zip.

Returns

ZipEntry

The ZipEntry added.

Remarks

Calling this method is equivalent to removing the ZipEntry for the given file name and directory path, if it exists, and then calling AddEntry(string, string). See the documentation for that method for further explanation. The string content is encoded using the default encoding for the machine. This encoding is distinct from the encoding used for the filename itself. See AlternateEncoding.

UpdateEntry(string, string, Encoding)

Updates the given entry in the ZipFile, using the given string as content for the ZipEntry.

public ZipEntry UpdateEntry(string entryName, string content, Encoding encoding)

Parameters

entryName string

The name, including any path, to use within the archive for the entry.

content string

The content of the file, should it be extracted from the zip.

encoding Encoding

The text encoding to use when encoding the string. Be aware: This is distinct from the text encoding used to encode the filename. See AlternateEncoding.

Returns

ZipEntry

The ZipEntry added.

Remarks

Calling this method is equivalent to removing the ZipEntry for the given file name and directory path, if it exists, and then calling AddEntry(string, string, Encoding). See the documentation for that method for further explanation.

UpdateFile(string)

Adds or Updates a File in a Zip file archive.

public ZipEntry UpdateFile(string fileName)

Parameters

fileName string

The name of the file to add or update. It should refer to a file in the filesystem. The name of the file may be a relative path or a fully-qualified path.

Returns

ZipEntry

The ZipEntry corresponding to the File that was added or updated.

Examples

This example shows how to Update an existing entry in a zipfile. The first call to UpdateFile adds the file to the newly-created zip archive. The second call to UpdateFile updates the content for that file in the zip archive.

using (ZipFile zip1 = new ZipFile())
{
  // UpdateFile might more accurately be called "AddOrUpdateFile"
  zip1.UpdateFile("MyDocuments\\Readme.txt");
  zip1.UpdateFile("CustomerList.csv");
  zip1.Comment = "This zip archive has been created.";
  zip1.Save("Content.zip");
}

using (ZipFile zip2 = ZipFile.Read("Content.zip"))
{
  zip2.UpdateFile("Updates\\Readme.txt");
  zip2.Comment = "This zip archive has been updated: The Readme.txt file has been changed.";
  zip2.Save();
}
Using zip1 As New ZipFile
    ' UpdateFile might more accurately be called "AddOrUpdateFile"
    zip1.UpdateFile("MyDocuments\Readme.txt")
    zip1.UpdateFile("CustomerList.csv")
    zip1.Comment = "This zip archive has been created."
    zip1.Save("Content.zip")
End Using

Using zip2 As ZipFile = ZipFile.Read("Content.zip")
    zip2.UpdateFile("Updates\Readme.txt")
    zip2.Comment = "This zip archive has been updated: The Readme.txt file has been changed."
    zip2.Save
End Using

Remarks

This method adds a file to a zip archive, or, if the file already exists in the zip archive, this method Updates the content of that given filename in the zip archive. The UpdateFile method might more accurately be called "AddOrUpdateFile".

Upon success, there is no way for the application to learn whether the file was added versus updated.

For ZipFile properties including Encryption, Password, SetCompression, ProvisionalAlternateEncoding, ExtractExistingFile, ZipErrorAction, and CompressionLevel, their respective values at the time of this call will be applied to the ZipEntry added.

See Also

UpdateFile(string, string)

Adds or Updates a File in a Zip file archive.

public ZipEntry UpdateFile(string fileName, string directoryPathInArchive)

Parameters

fileName string

The name of the file to add or update. It should refer to a file in the filesystem. The name of the file may be a relative path or a fully-qualified path.

directoryPathInArchive string

Specifies a directory path to use to override any path in the fileName. This path may, or may not, correspond to a real directory in the current filesystem. If the files within the zip are later extracted, this is the path used for the extracted file. Passing null (Nothing in VB) will use the path on the fileName, if any. Passing the empty string ("") will insert the item at the root path within the archive.

Returns

ZipEntry

The ZipEntry corresponding to the File that was added or updated.

Remarks

This method adds a file to a zip archive, or, if the file already exists in the zip archive, this method Updates the content of that given filename in the zip archive.

This version of the method allows the caller to explicitly specify the directory path to be used in the archive. The entry to be added or updated is found by using the specified directory path, combined with the basename of the specified filename.

Upon success, there is no way for the application to learn if the file was added versus updated.

For ZipFile properties including Encryption, Password, SetCompression, ProvisionalAlternateEncoding, ExtractExistingFile, ZipErrorAction, and CompressionLevel, their respective values at the time of this call will be applied to the ZipEntry added.

See Also

UpdateFiles(IEnumerable<string>)

Adds or updates a set of files in the ZipFile.

public void UpdateFiles(IEnumerable<string> fileNames)

Parameters

fileNames IEnumerable<string>

The collection of names of the files to update. Each string should refer to a file in the filesystem. The name of the file may be a relative path or a fully-qualified path.

Remarks

Any files that already exist in the archive are updated. Any files that don't yet exist in the archive are added.

For ZipFile properties including Encryption, Password, SetCompression, ProvisionalAlternateEncoding, ExtractExistingFile, ZipErrorAction, and CompressionLevel, their respective values at the time of this call will be applied to each ZipEntry added.

UpdateFiles(IEnumerable<string>, string)

Adds or updates a set of files to the ZipFile, using the specified directory path in the archive.

public void UpdateFiles(IEnumerable<string> fileNames, string directoryPathInArchive)

Parameters

fileNames IEnumerable<string>

The names of the files to add or update. Each string should refer to a file in the filesystem. The name of the file may be a relative path or a fully-qualified path.

directoryPathInArchive string

Specifies a directory path to use to override any path in the file name. This path may, or may not, correspond to a real directory in the current filesystem. If the files within the zip are later extracted, this is the path used for the extracted file. Passing null (Nothing in VB) will use the path on each of the fileNames, if any. Passing the empty string ("") will insert the item at the root path within the archive.

Remarks

Any files that already exist in the archive are updated. Any files that don't yet exist in the archive are added.

For ZipFile properties including Encryption, Password, SetCompression, ProvisionalAlternateEncoding, ExtractExistingFile, ZipErrorAction, and CompressionLevel, their respective values at the time of this call will be applied to each ZipEntry added.

See Also

UpdateItem(string)

Add or update a file or directory in the zip archive.

public void UpdateItem(string itemName)

Parameters

itemName string

the path to the file or directory to be added or updated.

Remarks

This is useful when the application is not sure or does not care if the item to be added is a file or directory, and does not know or does not care if the item already exists in the ZipFile. Calling this method is equivalent to calling RemoveEntry() if an entry by the same name already exists, followed calling by AddItem().

For ZipFile properties including Encryption, Password, SetCompression, ProvisionalAlternateEncoding, ExtractExistingFile, ZipErrorAction, and CompressionLevel, their respective values at the time of this call will be applied to the ZipEntry added.

See Also

UpdateItem(string, string)

Add or update a file or directory.

public void UpdateItem(string itemName, string directoryPathInArchive)

Parameters

itemName string

The path for the File or Directory to be added or updated.

directoryPathInArchive string

Specifies a directory path to use to override any path in the itemName. This path may, or may not, correspond to a real directory in the current filesystem. If the files within the zip are later extracted, this is the path used for the extracted file. Passing null (Nothing in VB) will use the path on the itemName, if any. Passing the empty string ("") will insert the item at the root path within the archive.

Remarks

This method is useful when the application is not sure or does not care if the item to be added is a file or directory, and does not know or does not care if the item already exists in the ZipFile. Calling this method is equivalent to calling RemoveEntry(), if an entry by that name exists, and then calling AddItem().

This version of the method allows the caller to explicitly specify the directory path to be used for the item being added to the archive. The entry or entries that are added or updated will use the specified DirectoryPathInArchive. Extracting the entry from the archive will result in a file stored in that directory path.

For ZipFile properties including Encryption, Password, SetCompression, ProvisionalAlternateEncoding, ExtractExistingFile, ZipErrorAction, and CompressionLevel, their respective values at the time of this call will be applied to the ZipEntry added.

See Also

UpdateSelectedFiles(string, string, string, bool)

Updates the ZipFile with a selection of files from the disk that conform to the specified criteria.

public void UpdateSelectedFiles(string selectionCriteria, string directoryOnDisk, string directoryPathInArchive, bool recurseDirectories)

Parameters

selectionCriteria string

The criteria for selection of files to add to the ZipFile.

directoryOnDisk string

The path to the directory in the filesystem from which to select files.

directoryPathInArchive string

Specifies a directory path to use to in place of the directoryOnDisk. This path may, or may not, correspond to a real directory in the current filesystem. If the files within the zip are later extracted, this is the path used for the extracted file. Passing null (nothing in VB) will use the path on the file name, if any; in other words it would use directoryOnDisk, plus any subdirectory. Passing the empty string ("") will insert the item at the root path within the archive.

recurseDirectories bool

If true, the method also scans subdirectories for files matching the criteria.

Remarks

This method selects files from the specified disk directory that match the specified selection criteria, and Updates the ZipFile with those files, using the specified directory path in the archive. If recurseDirectories is true, files are also selected from subdirectories, and the directory structure in the filesystem is reproduced in the zip archive, rooted at the directory specified by directoryOnDisk. For details on the syntax for the selectionCriteria parameter, see AddSelectedFiles(string).

See Also

Events

AddProgress

An event handler invoked before, during, and after Adding entries to a zip archive.

public event EventHandler<AddProgressEventArgs> AddProgress

Event Type

EventHandler<AddProgressEventArgs>

Examples

int _numEntriesToAdd= 0;
int _numEntriesAdded= 0;
void AddProgressHandler(object sender, AddProgressEventArgs element)
{
    switch (element.EventType)
    {
        case ZipProgressEventType.Adding_Started:
            Console.WriteLine("Adding files to the zip...");
            break;
        case ZipProgressEventType.Adding_AfterAddEntry:
            _numEntriesAdded++;
            Console.WriteLine(String.Format("Adding file {0}/{1} :: {2}",
                                     _numEntriesAdded, _numEntriesToAdd, element.CurrentEntry.FileName));
            break;
        case ZipProgressEventType.Adding_Completed:
            Console.WriteLine("Added all files");
            break;
    }
}

void CreateTheZip()
{
    using (ZipFile zip = new ZipFile())
    {
        zip.AddProgress += AddProgressHandler;
        zip.AddDirectory(System.IO.Path.GetFileName(DirToZip));
        zip.Save(ZipFileToCreate);
    }
}
Private Sub AddProgressHandler(ByVal sender As Object, ByVal element As AddProgressEventArgs)
    Select Case element.EventType
        Case ZipProgressEventType.Adding_Started
            Console.WriteLine("Adding files to the zip...")
            Exit Select
        Case ZipProgressEventType.Adding_AfterAddEntry
            Console.WriteLine(String.Format("Adding file {0}", element.CurrentEntry.FileName))
            Exit Select
        Case ZipProgressEventType.Adding_Completed
            Console.WriteLine("Added all files")
            Exit Select
    End Select
End Sub

Sub CreateTheZip()
    Using zip as ZipFile = New ZipFile
        AddHandler zip.AddProgress, AddressOf AddProgressHandler
        zip.AddDirectory(System.IO.Path.GetFileName(DirToZip))
        zip.Save(ZipFileToCreate);
    End Using
End Sub

Remarks

Adding a large number of entries to a zip file can take a long time. For example, when calling AddDirectory(string) on a directory that contains 50,000 files, it could take 3 minutes or so. This event handler allws an application to track the progress of the Add operation, and to optionally cancel a lengthy Add operation.

See Also

ExtractProgress

An event handler invoked before, during, and after extraction of entries in the zip archive.

public event EventHandler<ExtractProgressEventArgs> ExtractProgress

Event Type

EventHandler<ExtractProgressEventArgs>

Examples

private static bool justHadByteUpdate = false;
public static void ExtractProgress(object sender, ExtractProgressEventArgs element)
{
  if(element.EventType == ZipProgressEventType.Extracting_EntryBytesWritten)
  {
    if (justHadByteUpdate)
      Console.SetCursorPosition(0, Console.CursorTop);

    Console.Write("   {0}/{1} ({2:N0}%)", element.BytesTransferred, element.TotalBytesToTransfer,
                  element.BytesTransferred / (0.01 * element.TotalBytesToTransfer ));
    justHadByteUpdate = true;
  }
  else if(element.EventType == ZipProgressEventType.Extracting_BeforeExtractEntry)
  {
    if (justHadByteUpdate)
      Console.WriteLine();
    Console.WriteLine("Extracting: {0}", element.CurrentEntry.FileName);
    justHadByteUpdate= false;
  }
}

public static ExtractZip(string zipToExtract, string directory)
{
  string TargetDirectory= "extract";
  using (var zip = ZipFile.Read(zipToExtract)) {
    zip.ExtractProgress += ExtractProgress;
    foreach (var element in zip1)
    {
      element.Extract(TargetDirectory, true);
    }
  }
}
Public Shared Sub Main(ByVal args As String())
    Dim ZipToUnpack As String = "C1P3SML.zip"
    Dim TargetDir As String = "ExtractTest_Extract"
    Console.WriteLine("Extracting file {0} to {1}", ZipToUnpack, TargetDir)
    Using zip1 As ZipFile = ZipFile.Read(ZipToUnpack)
        AddHandler zip1.ExtractProgress, AddressOf MyExtractProgress
        Dim element As ZipEntry
        For Each element In zip1
            element.Extract(TargetDir, True)
        Next
    End Using
End Sub

Private Shared justHadByteUpdate As Boolean = False

Public Shared Sub MyExtractProgress(ByVal sender As Object, ByVal element As ExtractProgressEventArgs)
    If (element.EventType = ZipProgressEventType.Extracting_EntryBytesWritten) Then
        If ExtractTest.justHadByteUpdate Then
            Console.SetCursorPosition(0, Console.CursorTop)
        End If
        Console.Write("   {0}/{1} ({2:N0}%)", element.BytesTransferred, element.TotalBytesToTransfer, (CDbl(element.BytesTransferred) / (0.01 * element.TotalBytesToTransfer)))
        ExtractTest.justHadByteUpdate = True
    ElseIf (element.EventType = ZipProgressEventType.Extracting_BeforeExtractEntry) Then
        If ExtractTest.justHadByteUpdate Then
            Console.WriteLine
        End If
        Console.WriteLine("Extracting: {0}", element.CurrentEntry.FileName)
        ExtractTest.justHadByteUpdate = False
    End If
End Sub

Remarks

Depending on the particular event, different properties on the ExtractProgressEventArgs parameter are set. The following table summarizes the available EventTypes and the conditions under which this event handler is invoked with a ExtractProgressEventArgs with the given EventType.

value of EntryTypeMeaning and conditions
ZipProgressEventType.Extracting_BeforeExtractAll Set when ExtractAll() begins. The ArchiveName, Overwrite, and ExtractLocation properties are meaningful.
ZipProgressEventType.Extracting_AfterExtractAll Set when ExtractAll() has completed. The ArchiveName, Overwrite, and ExtractLocation properties are meaningful.
ZipProgressEventType.Extracting_BeforeExtractEntry Set when an Extract() on an entry in the ZipFile has begun. Properties that are meaningful: ArchiveName, EntriesTotal, CurrentEntry, Overwrite, ExtractLocation, EntriesExtracted.
ZipProgressEventType.Extracting_AfterExtractEntry Set when an Extract() on an entry in the ZipFile has completed. Properties that are meaningful: ArchiveName, EntriesTotal, CurrentEntry, Overwrite, ExtractLocation, EntriesExtracted.
ZipProgressEventType.Extracting_EntryBytesWritten Set within a call to Extract() on an entry in the ZipFile, as data is extracted for the entry. Properties that are meaningful: ArchiveName, CurrentEntry, BytesTransferred, TotalBytesToTransfer.
ZipProgressEventType.Extracting_ExtractEntryWouldOverwrite Set within a call to Extract() on an entry in the ZipFile, when the extraction would overwrite an existing file. This event type is used only when ExtractExistingFileAction on the ZipFile or ZipEntry is set to InvokeExtractProgressEvent.
See Also

ReadProgress

An event handler invoked before, during, and after the reading of a zip archive.

public event EventHandler<ReadProgressEventArgs> ReadProgress

Event Type

EventHandler<ReadProgressEventArgs>

Remarks

Depending on the particular event being signaled, different properties on the ReadProgressEventArgs parameter are set. The following table summarizes the available EventTypes and the conditions under which this event handler is invoked with a ReadProgressEventArgs with the given EventType.

value of EntryTypeMeaning and conditions
ZipProgressEventType.Reading_StartedFired just as ZipFile.Read() begins. Meaningful properties: ArchiveName.
ZipProgressEventType.Reading_CompletedFired when ZipFile.Read() has completed. Meaningful properties: ArchiveName.
ZipProgressEventType.Reading_ArchiveBytesReadFired while reading, updates the number of bytes read for the entire archive. Meaningful properties: ArchiveName, CurrentEntry, BytesTransferred, TotalBytesToTransfer.
ZipProgressEventType.Reading_BeforeReadEntryIndicates an entry is about to be read from the archive. Meaningful properties: ArchiveName, EntriesTotal.
ZipProgressEventType.Reading_AfterReadEntryIndicates an entry has just been read from the archive. Meaningful properties: ArchiveName, EntriesTotal, CurrentEntry.
See Also

SaveProgress

An event handler invoked when a Save() starts, before and after each entry has been written to the archive, when a Save() completes, and during other Save events.

public event EventHandler<SaveProgressEventArgs> SaveProgress

Event Type

EventHandler<SaveProgressEventArgs>

Examples

This example uses an anonymous method to handle the SaveProgress event, by updating a progress bar.

progressBar1.Value = 0;
progressBar1.Max = listbox1.Items.Count;
using (ZipFile zip = new ZipFile())
{
   // listbox1 contains a list of filenames
   zip.AddFiles(listbox1.Items);

   // do the progress bar:
   zip.SaveProgress += (sender, element) => {
      if (element.EventType == ZipProgressEventType.Saving_BeforeWriteEntry) {
         progressBar1.PerformStep();
      }
   };

   zip.Save(fs);
}

This example uses a named method as the SaveProgress event handler, to update the user, in a console-based application.

static bool justHadByteUpdate= false;
public static void SaveProgress(object sender, SaveProgressEventArgs element)
{
    if (element.EventType == ZipProgressEventType.Saving_Started)
        Console.WriteLine("Saving: {0}", element.ArchiveName);

    else if (element.EventType == ZipProgressEventType.Saving_Completed)
    {
        justHadByteUpdate= false;
        Console.WriteLine();
        Console.WriteLine("Done: {0}", element.ArchiveName);
    }

    else if (element.EventType == ZipProgressEventType.Saving_BeforeWriteEntry)
    {
        if (justHadByteUpdate)
            Console.WriteLine();
        Console.WriteLine("  Writing: {0} ({1}/{2})",
                          element.CurrentEntry.FileName, element.EntriesSaved, element.EntriesTotal);
        justHadByteUpdate= false;
    }

    else if (element.EventType == ZipProgressEventType.Saving_EntryBytesRead)
    {
        if (justHadByteUpdate)
            Console.SetCursorPosition(0, Console.CursorTop);
         Console.Write("     {0}/{1} ({2:N0}%)", element.BytesTransferred, element.TotalBytesToTransfer,
                      element.BytesTransferred / (0.01 * element.TotalBytesToTransfer ));
        justHadByteUpdate= true;
    }
}

public static ZipUp(string targetZip, string directory)
{
  using (var zip = new ZipFile()) {
    zip.SaveProgress += SaveProgress;
    zip.AddDirectory(directory);
    zip.Save(targetZip);
  }
}
Public Sub ZipUp(ByVal targetZip As String, ByVal directory As String)
    Using zip As ZipFile = New ZipFile
        AddHandler zip.SaveProgress, AddressOf MySaveProgress
        zip.AddDirectory(directory)
        zip.Save(targetZip)
    End Using
End Sub

Private Shared justHadByteUpdate As Boolean = False

Public Shared Sub MySaveProgress(ByVal sender As Object, ByVal element As SaveProgressEventArgs)
    If (element.EventType Is ZipProgressEventType.Saving_Started) Then
        Console.WriteLine("Saving: {0}", element.ArchiveName)

    ElseIf (element.EventType Is ZipProgressEventType.Saving_Completed) Then
        justHadByteUpdate = False
        Console.WriteLine
        Console.WriteLine("Done: {0}", element.ArchiveName)

    ElseIf (element.EventType Is ZipProgressEventType.Saving_BeforeWriteEntry) Then
        If justHadByteUpdate Then
            Console.WriteLine
        End If
        Console.WriteLine("  Writing: {0} ({1}/{2})", element.CurrentEntry.FileName, element.EntriesSaved, element.EntriesTotal)
        justHadByteUpdate = False

    ElseIf (element.EventType Is ZipProgressEventType.Saving_EntryBytesRead) Then
        If justHadByteUpdate Then
            Console.SetCursorPosition(0, Console.CursorTop)
        End If
        Console.Write("     {0}/{1} ({2:N0}%)", element.BytesTransferred, _
                      element.TotalBytesToTransfer, _
                      (CDbl(element.BytesTransferred) / (0.01 * element.TotalBytesToTransfer)))
        justHadByteUpdate = True
    End If
End Sub

This is a more complete example of using the SaveProgress events in a Windows Forms application, with a Thread object.

delegate void SaveEntryProgress(SaveProgressEventArgs element);
delegate void ButtonClick(object sender, EventArgs element);

public class WorkerOptions
{
    public string ZipName;
    public string Folder;
    public string Encoding;
    public string Comment;
    public int ZipFlavor;
    public Zip64Option Zip64;
}

private int _progress2MaxFactor;
private bool _saveCanceled;
private long _totalBytesBeforeCompress;
private long _totalBytesAfterCompress;
private Thread _workerThread;


private void btnZipup_Click(object sender, EventArgs element)
{
    KickoffZipup();
}

private void btnCancel_Click(object sender, EventArgs element)
{
    if (this.lblStatus.InvokeRequired)
    {
        this.lblStatus.Invoke(new ButtonClick(this.btnCancel_Click), new object[] { sender, element });
    }
    else
    {
        _saveCanceled = true;
        lblStatus.Text = "Canceled...";
        ResetState();
    }
}

private void KickoffZipup()
{
    _folderName = tbDirName.Text;

    if (_folderName == null || _folderName == "") return;
    if (this.tbZipName.Text == null || this.tbZipName.Text == "") return;

    // check for existence of the zip file:
    if (System.IO.File.Exists(this.tbZipName.Text))
    {
        var dlgResult = MessageBox.Show(String.Format("The file you have specified ({0}) already exists." +
                                                      "  Do you want to overwrite this file?", this.tbZipName.Text),
                                        "Confirmation is Required", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
        if (dlgResult != DialogResult.Yes) return;
        System.IO.File.Delete(this.tbZipName.Text);
    }

     _saveCanceled = false;
    _nFilesCompleted = 0;
    _totalBytesAfterCompress = 0;
    _totalBytesBeforeCompress = 0;
    this.btnOk.Enabled = false;
    this.btnOk.Text = "Zipping...";
    this.btnCancel.Enabled = true;
    lblStatus.Text = "Zipping...";

    var options = new WorkerOptions
    {
        ZipName = this.tbZipName.Text,
        Folder = _folderName,
        Encoding = "ibm437"
    };

    if (this.comboBox1.SelectedIndex != 0)
    {
        options.Encoding = this.comboBox1.SelectedItem.ToString();
    }

    if (this.radioFlavorSfxCmd.Checked)
        options.ZipFlavor = 2;
    else if (this.radioFlavorSfxGui.Checked)
        options.ZipFlavor = 1;
    else options.ZipFlavor = 0;

    if (this.radioZip64AsNecessary.Checked)
        options.Zip64 = Zip64Option.AsNecessary;
    else if (this.radioZip64Always.Checked)
        options.Zip64 = Zip64Option.Always;
    else options.Zip64 = Zip64Option.Never;

    options.Comment = String.Format("Encoding:{0} || Flavor:{1} || ZIP64:{2}\r\nCreated at {3} || {4}\r\n",
                options.Encoding,
                FlavorToString(options.ZipFlavor),
                options.Zip64.ToString(),
                System.DateTime.Now.ToString("yyyy-MMM-dd HH:mm:ss"),
                this.Text);

    if (this.tbComment.Text != TB_COMMENT_NOTE)
        options.Comment += this.tbComment.Text;

    _workerThread = new Thread(this.DoSave);
    _workerThread.Name = "Zip Saver thread";
    _workerThread.Start(options);
    this.Cursor = Cursors.WaitCursor;
 }


private void DoSave(Object p)
{
    WorkerOptions options = p as WorkerOptions;
    try
    {
        using (var zip1 = new ZipFile())
        {
            zip1.ProvisionalAlternateEncoding = System.Text.Encoding.GetEncoding(options.Encoding);
            zip1.Comment = options.Comment;
            zip1.AddDirectory(options.Folder);
            _entriesToZip = zip1.EntryFileNames.Count;
            SetProgressBars();
            zip1.SaveProgress += this.zip1_SaveProgress;

            zip1.UseZip64WhenSaving = options.Zip64;

            if (options.ZipFlavor == 1)
                zip1.SaveSelfExtractor(options.ZipName, SelfExtractorFlavor.WinFormsApplication);
            else if (options.ZipFlavor == 2)
                zip1.SaveSelfExtractor(options.ZipName, SelfExtractorFlavor.ConsoleApplication);
            else
                zip1.Save(options.ZipName);
        }
    }
    catch (System.Exception exc1)
    {
        MessageBox.Show(String.Format("Exception while zipping: {0}", exc1.Message));
        btnCancel_Click(null, null);
    }
}



void zip1_SaveProgress(object sender, SaveProgressEventArgs element)
{
    switch (element.EventType)
    {
        case ZipProgressEventType.Saving_AfterWriteEntry:
            StepArchiveProgress(element);
            break;
        case ZipProgressEventType.Saving_EntryBytesRead:
            StepEntryProgress(element);
            break;
        case ZipProgressEventType.Saving_Completed:
            SaveCompleted();
            break;
        case ZipProgressEventType.Saving_AfterSaveTempArchive:
            // this event only occurs when saving an SFX file
            TempArchiveSaved();
            break;
    }
    if (_saveCanceled)
        element.Cancel = true;
}



private void StepArchiveProgress(SaveProgressEventArgs element)
{
    if (this.progressBar1.InvokeRequired)
    {
        this.progressBar1.Invoke(new SaveEntryProgress(this.StepArchiveProgress), new object[] { element });
    }
    else
    {
        if (!_saveCanceled)
        {
            _nFilesCompleted++;
            this.progressBar1.PerformStep();
            _totalBytesAfterCompress += element.CurrentEntry.CompressedSize;
            _totalBytesBeforeCompress += element.CurrentEntry.UncompressedSize;

            // reset the progress bar for the entry:
            this.progressBar2.Value = this.progressBar2.Maximum = 1;

            this.Update();
        }
    }
}


private void StepEntryProgress(SaveProgressEventArgs element)
{
    if (this.progressBar2.InvokeRequired)
    {
        this.progressBar2.Invoke(new SaveEntryProgress(this.StepEntryProgress), new object[] { element });
    }
    else
    {
        if (!_saveCanceled)
        {
            if (this.progressBar2.Maximum == 1)
            {
                // reset
                Int64 max = element.TotalBytesToTransfer;
                _progress2MaxFactor = 0;
                while (max > System.Int32.MaxValue)
                {
                    max /= 2;
                    _progress2MaxFactor++;
                }
                this.progressBar2.Maximum = (int)max;
                lblStatus.Text = String.Format("{0} of {1} files...({2})",
                    _nFilesCompleted + 1, _entriesToZip, element.CurrentEntry.FileName);
            }

             int xferred = element.BytesTransferred >> _progress2MaxFactor;

             this.progressBar2.Value = (xferred >= this.progressBar2.Maximum)
                ? this.progressBar2.Maximum
                : xferred;

             this.Update();
        }
    }
}

private void SaveCompleted()
{
    if (this.lblStatus.InvokeRequired)
    {
        this.lblStatus.Invoke(new MethodInvoker(this.SaveCompleted));
    }
    else
    {
        lblStatus.Text = String.Format("Done, Compressed {0} files, {1:N0}% of original.",
            _nFilesCompleted, (100.00 * _totalBytesAfterCompress) / _totalBytesBeforeCompress);
         ResetState();
    }
}

private void ResetState()
{
    this.btnCancel.Enabled = false;
    this.btnOk.Enabled = true;
    this.btnOk.Text = "Zip it!";
    this.progressBar1.Value = 0;
    this.progressBar2.Value = 0;
    this.Cursor = Cursors.Default;
    if (!_workerThread.IsAlive)
        _workerThread.Join();
}

Remarks

Depending on the particular event, different properties on the SaveProgressEventArgs parameter are set. The following table summarizes the available EventTypes and the conditions under which this event handler is invoked with a SaveProgressEventArgs with the given EventType.

value of EntryTypeMeaning and conditions
ZipProgressEventType.Saving_StartedFired when ZipFile.Save() begins.
ZipProgressEventType.Saving_BeforeSaveEntry Fired within ZipFile.Save(), just before writing data for each particular entry.
ZipProgressEventType.Saving_AfterSaveEntry Fired within ZipFile.Save(), just after having finished writing data for each particular entry.
ZipProgressEventType.Saving_CompletedFired when ZipFile.Save() has completed.
ZipProgressEventType.Saving_AfterSaveTempArchive Fired after the temporary file has been created. This happens only when saving to a disk file. This event will not be invoked when saving to a stream.
ZipProgressEventType.Saving_BeforeRenameTempArchive Fired just before renaming the temporary file to the permanent location. This happens only when saving to a disk file. This event will not be invoked when saving to a stream.
ZipProgressEventType.Saving_AfterRenameTempArchive Fired just after renaming the temporary file to the permanent location. This happens only when saving to a disk file. This event will not be invoked when saving to a stream.
ZipProgressEventType.Saving_AfterCompileSelfExtractor Fired after a self-extracting archive has finished compiling. This EventType is used only within SaveSelfExtractor().
ZipProgressEventType.Saving_BytesRead Set during the save of a particular entry, to update progress of the Save(). When this EventType is set, the BytesTransferred is the number of bytes that have been read from the source stream. The TotalBytesToTransfer is the number of bytes in the uncompressed file.
See Also

ZipError

An event that is raised when an error occurs during open or read of files while saving a zip archive.

public event EventHandler<ZipErrorEventArgs> ZipError

Event Type

EventHandler<ZipErrorEventArgs>

Examples

This example shows how to use an event handler to handle errors during save of the zip file.

public static void MyZipError(object sender, ZipErrorEventArgs element)
{
    Console.WriteLine("Error saving {0}...", element.FileName);
    Console.WriteLine("   Exception: {0}", element.exception);
    ZipEntry entry = element.CurrentEntry;
    string response = null;
    // Ask the user whether he wants to skip this error or not
    do
    {
        Console.Write("Retry, Skip, Throw, or Cancel ? (R/S/T/C) ");
        response = Console.ReadLine();
        Console.WriteLine();

    } while (response != null &&
             response[0]!='S' && response[0]!='s' &&
             response[0]!='R' && response[0]!='r' &&
             response[0]!='T' && response[0]!='t' &&
             response[0]!='C' && response[0]!='c');

    element.Cancel = (response[0]=='C' || response[0]=='c');

    if (response[0]=='S' || response[0]=='s')
        entry.ZipErrorAction = ZipErrorAction.Skip;
    else if (response[0]=='R' || response[0]=='r')
        entry.ZipErrorAction = ZipErrorAction.Retry;
    else if (response[0]=='T' || response[0]=='t')
        entry.ZipErrorAction = ZipErrorAction.Throw;
}

public void SaveTheFile()
{
  string directoryToZip = "fodder";
  string directoryInArchive = "files";
  string zipFileToCreate = "Archive.zip";
  using (var zip = new ZipFile())
  {
    // set the event handler before adding any entries
    zip.ZipError += MyZipError;
    zip.AddDirectory(directoryToZip, directoryInArchive);
    zip.Save(zipFileToCreate);
  }
}
Private Sub MyZipError(ByVal sender As Object, ByVal element As Ionic.Zip.ZipErrorEventArgs)
    ' At this point, the application could prompt the user for an action to take.
    ' But in this case, this application will simply automatically skip the file, in case of error.
    Console.WriteLine("Zip Error,  entry {0}", element.CurrentEntry.FileName)
    Console.WriteLine("   Exception: {0}", element.exception)
    ' set the desired ZipErrorAction on the CurrentEntry to communicate that to DotNetZip
    element.CurrentEntry.ZipErrorAction = Zip.ZipErrorAction.Skip
End Sub

Public Sub SaveTheFile()
    Dim directoryToZip As String = "fodder"
    Dim directoryInArchive As String = "files"
    Dim zipFileToCreate as String = "Archive.zip"
    Using zipArchive As ZipFile = New ZipFile
        ' set the event handler before adding any entries
        AddHandler zipArchive.ZipError, AddressOf MyZipError
        zipArchive.AddDirectory(directoryToZip, directoryInArchive)
        zipArchive.Save(zipFileToCreate)
    End Using
End Sub

Remarks

Errors can occur as a file is being saved to the zip archive. For example, the File.Open may fail, or a File.Read may fail, because of lock conflicts or other reasons. If you add a handler to this event, you can handle such errors in your own code. If you don't add a handler, the library will throw an exception if it encounters an I/O error during a call to Save().

Setting a handler implicitly sets ZipErrorAction to ZipErrorAction.InvokeErrorEvent.

The handler you add applies to all ZipEntry items that are subsequently added to the ZipFile instance. If you set this property after you have added items to the ZipFile, but before you have called Save(), errors that occur while saving those items will not cause the error handler to be invoked.

If you want to handle any errors that occur with any entry in the zip file using the same error handler, then add your error handler once, before adding any entries to the zip archive.

In the error handler method, you need to set the ZipErrorAction property on the ZipErrorEventArgs.CurrentEntry. This communicates back to DotNetZip what you would like to do with this particular error. Within an error handler, if you set the ZipEntry.ZipErrorAction property on the ZipEntry to ZipErrorAction.InvokeErrorEvent or if you don't set it at all, the library will throw the exception. (It is the same as if you had set the ZipEntry.ZipErrorAction property on the ZipEntry to ZipErrorAction.Throw.) If you set the ZipErrorEventArgs.Cancel to true, the entire Save() will be canceled.

In the case that you use ZipErrorAction.Skip, implying that you want to skip the entry for which there's been an error, DotNetZip tries to seek backwards in the output stream, and truncate all bytes written on behalf of that particular entry. This works only if the output stream is seekable. It will not work, for example, when using ASPNET's Response.OutputStream.

See Also