The ZipWriter class lets an application create a Zip archive without resorting to intermediate storage (either memory or disk). Furthermore, the creation of the Zip archive starts as soon as the ZipWriter object has data to compress: the resulting Zip archive is immediately available for processing, for example by an application using a ZipReader object receiving the archive over an FTP connection. The target Zip archive is passed to the ZipWriter's class constructor as a stream of any type.
The main methods of the ZipWriter class used to create Zip archives are WriteItemLocalHeader (in conjunction with a ZipItemLocalHeader object), WriteItemData, and CloseZipFile. The class also provides a ByteProgression event to monitor the progression of the Zip creation operation. For details on the events used by Xceed Real-Time Zip for .NET / .NET CF, see Events.
The following diagram will help to illustrate the relationship between the structure of a Zip archive and the class methods you must use to create a Zip archive.
Red boxes: Local header
Blue boxes: Compressed data
Green boxes: Data descriptor
Grey boxes: Central headers that make up the central directory
The Zip file format can store item sizes and offsets in either 4-byte fields or 8-byte fields. This yields limits of 4GB and about 18 million terabytes (more precisely, 2^64 - 1 bytes), respectively. Using 8-byte fields is known as Zip64 extensions to the Zip file format. The original and most widely implemented specification, version 2.0, of the Zip format only supports 4-byte fields. Zip64 extensions were introduced in version 4.5 of the specification.
Most modern Zip utilities support Zip64 extensions seamlessly. But a few old or broken Zip implementations still do not. For the sake of interoperability, the ZipWriter class uses 4-byte fields by default. Zip64 extensions can still be enabled when constructing a ZipWriter instance.
This differs from previous versions of Xceed Real-Time Zip for .NET. Versions 4.2 and below always used Zip64 extensions. In more recent versions, Zip64 extensions are only used when explicitly enabled in the constructor.
An automatic mode where Zip64 extensions would be used when a 4GB+ item is detected isn't possible because that would cause the ZipWriter to seek in the target stream and correct some fields in a local header that's already been written.
WinRar, Zip tools on MacOS, and the built-in Zip support in Windows XP are known to lack support for the Zip64 extensions. So before creating a Zip archive, a decision must be made as to whether that archive will require Zip64 extensions or not. Here are the limits for the default behavior:
If these limits are likely to be broken or you want to be able to create Zip archives in every scenario, enable Zip64 extensions by setting the allowZip64Extensions parameter to true in the ZipWriter constructor.
When creating a Zip archive, a stream representing the target archive is first passed to the ZipWriter constructor along with a boolean value indicating whether Zip64 extensions are to be used. A local header is then created for the first item to be archived and is written to the archive (red boxes in the diagram), followed by the item's data (blue boxes). This process is repeated until all of the items have been processed. Finally, the Zip archive is closed.
An item's local header is represented by a ZipItemLocalHeader object, which is written to the Zip archive using the WriteItemLocalHeader method. The encryption method/password, and compression level/method can optionally be specified when creating a ZipItemLocalHeader. See The ZipItemLocalHeader class for more details.
The current item's data is written by calling WriteItemData until all of its data has been written to the archive. The WriteItemData method is very similar to the Write method of the Stream class: the data to be written is passed to it as an array of bytes, with an offset indicating at what point to begin copying in the buffer and a count indicating the number of bytes to write from the offset.
There are several flavors of WriteItemData to accommodate different data scenarios and make efficient reuse of data buffers.
Another way to write data is to expose the item's data as a write-only Stream object with the GetItemDataStream method. Each call to the stream's Write method will call WriteItemData. This makes it possible to integrate ZipWriter with other classes that use the Stream class interface without the need for "glue code."
Once an item's data has been written, calling WriteItemLocalHeader with the header for the next item automatically causes the data descriptor (green boxes) of the previous item to be written.
Once the local headers and data of all the items have been written, CloseZipFile must be called to cause the data descriptor of the final item to be written, as well as the central directory (grey boxes) of the Zip archive.
The ZipWriter class writes all items with the UTF8Filename and UTF8Comment extra headers, but only if non-ASCII characters are used in the text. This corresponds to the UnicodeUsagePolicy.NonASCIIOnly value in Xceed Zip .NET.
Note that it doesn't write the old Xceed Unicode extra header, as it is deprecated.
Xceed Real-Time Zip for .NET does not support the creation of split/spanned or self-extracting archives
Example 1: Creating a Zip archive using ZipWriter
The following example demonstrates how to create a Zip archive locally using the files in a test directory.