Table of Contents

Class ZipInputStream

Namespace
Ionic.Zip
Assembly
SunamoDotNetZip.dll

Provides a stream metaphor for reading zip files.

public class ZipInputStream : Stream, IAsyncDisposable, IDisposable
Inheritance
ZipInputStream
Implements
Inherited Members
Extension Methods

Remarks

This class provides an alternative programming model for reading zip files to the one enabled by the ZipFile class. Use this when reading zip files, as an alternative to the ZipFile class, when you would like to use a Stream class to read the file.

Some application designs require a readable stream for input. This stream can be used to read a zip file, and extract entries.

Both the ZipInputStream class and the ZipFile class can be used to read and extract zip files. Both of them support many of the common zip features, including Unicode, different compression levels, and ZIP64. The programming models differ. For example, when extracting entries via calls to the GetNextEntry() and Read() methods on the ZipInputStream class, the caller is responsible for creating the file, writing the bytes into the file, setting the attributes on the file, and setting the created, last modified, and last accessed timestamps on the file. All of these things are done automatically by a call to ZipEntry.Extract(). For this reason, the ZipInputStream is generally recommended for when your application wants to extract the data, without storing that data into a file.

Aside from the obvious differences in programming model, there are some differences in capability between the ZipFile class and the ZipInputStream class.

  • ZipFile can be used to create or update zip files, or read and extract zip files. ZipInputStream can be used only to read and extract zip files. If you want to use a stream to create zip files, check out the ZipOutputStream.
  • ZipInputStream cannot read segmented or spanned zip files.
  • ZipInputStream will not read Zip file comments.
  • When reading larger files, ZipInputStream will always underperform ZipFile. This is because the ZipInputStream does a full scan on the zip file, while the ZipFile class reads the central directory of the zip file.

Constructors

ZipInputStream(Stream)

Create a ZipInputStream, wrapping it around an existing stream.

public ZipInputStream(Stream stream)

Parameters

stream Stream

The stream to read. It must be readable. This stream will be closed at the time the ZipInputStream is closed.

Examples

This example shows how to read a zip file, and extract entries, using the ZipInputStream class.

private void Unzip()
{
    byte[] buffer= new byte[2048];
    int n;
    using (var raw = File.Open(inputFileName, FileMode.Open, FileAccess.Read))
    {
        using (var input= new ZipInputStream(raw))
        {
            ZipEntry e;
            while (( e = input.GetNextEntry()) != null)
            {
                if (e.IsDirectory) continue;
                string outputPath = Path.Combine(extractDir, e.FileName);
                using (var output = File.Open(outputPath, FileMode.Create, FileAccess.ReadWrite))
                {
                    while ((n= input.Read(buffer, 0, buffer.Length)) > 0)
                    {
                        output.Write(buffer,0,n);
                    }
                }
            }
        }
    }
}
Private Sub UnZip()
    Dim inputFileName As String = "MyArchive.zip"
    Dim extractDir As String = "extract"
    Dim buffer As Byte() = New Byte(2048) {}
    Using raw As FileStream = File.Open(inputFileName, FileMode.Open, FileAccess.Read)
        Using input As ZipInputStream = New ZipInputStream(raw)
            Dim e As ZipEntry
            Do While (Not e = input.GetNextEntry Is Nothing)
                If Not e.IsDirectory Then
                    Using output As FileStream = File.Open(Path.Combine(extractDir, e.FileName), _
                                                           FileMode.Create, FileAccess.ReadWrite)
                        Dim n As Integer
                        Do While (n = input.Read(buffer, 0, buffer.Length) > 0)
                            output.Write(buffer, 0, n)
                        Loop
                    End Using
                End If
            Loop
        End Using
    End Using
End Sub

Remarks

While the ZipFile class is generally easier to use, this class provides an alternative to those applications that want to read from a zipfile directly, using a Stream.

Both the ZipInputStream class and the ZipFile class can be used to read and extract zip files. Both of them support many of the common zip features, including Unicode, different compression levels, and ZIP64. The programming models differ. For example, when extracting entries via calls to the GetNextEntry() and Read() methods on the ZipInputStream class, the caller is responsible for creating the file, writing the bytes into the file, setting the attributes on the file, and setting the created, last modified, and last accessed timestamps on the file. All of these things are done automatically by a call to ZipEntry.Extract(). For this reason, the ZipInputStream is generally recommended for when your application wants to extract the data, without storing that data into a file.

Aside from the obvious differences in programming model, there are some differences in capability between the ZipFile class and the ZipInputStream class.

  • ZipFile can be used to create or update zip files, or read and extract zip files. ZipInputStream can be used only to read and extract zip files. If you want to use a stream to create zip files, check out the ZipOutputStream.
  • ZipInputStream cannot read segmented or spanned zip files.
  • ZipInputStream will not read Zip file comments.
  • When reading larger files, ZipInputStream will always underperform ZipFile. This is because the ZipInputStream does a full scan on the zip file, while the ZipFile class reads the central directory of the zip file.

ZipInputStream(Stream, bool)

Create a ZipInputStream, explicitly specifying whether to keep the underlying stream open.

public ZipInputStream(Stream stream, bool leaveOpen)

Parameters

stream Stream

The stream to read from. It must be readable.

leaveOpen bool

true if the application would like the stream to remain open after the ZipInputStream has been closed.

Remarks

See the documentation for the ZipInputStream(Stream) constructor for a discussion of the class, and an example of how to use the class.

ZipInputStream(string)

Create a ZipInputStream, given the name of an existing zip file.

public ZipInputStream(string fileName)

Parameters

fileName string

The name of the filesystem file to read.

Examples

This example shows how to read a zip file, and extract entries, using the ZipInputStream class.

private void Unzip()
{
    byte[] buffer= new byte[2048];
    int n;
    using (var input= new ZipInputStream(inputFileName))
    {
        ZipEntry e;
        while (( e = input.GetNextEntry()) != null)
        {
            if (e.IsDirectory) continue;
            string outputPath = Path.Combine(extractDir, e.FileName);
            using (var output = File.Open(outputPath, FileMode.Create, FileAccess.ReadWrite))
            {
                while ((n= input.Read(buffer, 0, buffer.Length)) > 0)
                {
                    output.Write(buffer,0,n);
                }
            }
        }
    }
}
Private Sub UnZip()
    Dim inputFileName As String = "MyArchive.zip"
    Dim extractDir As String = "extract"
    Dim buffer As Byte() = New Byte(2048) {}
    Using input As ZipInputStream = New ZipInputStream(inputFileName)
        Dim e As ZipEntry
        Do While (Not e = input.GetNextEntry Is Nothing)
            If Not e.IsDirectory Then
                Using output As FileStream = File.Open(Path.Combine(extractDir, e.FileName), _
                                                       FileMode.Create, FileAccess.ReadWrite)
                    Dim n As Integer
                    Do While (n = input.Read(buffer, 0, buffer.Length) > 0)
                        output.Write(buffer, 0, n)
                    Loop
                End Using
            End If
        Loop
    End Using
End Sub

Remarks

This constructor opens a FileStream for the given zipfile, and wraps a ZipInputStream around that. See the documentation for the ZipInputStream(Stream) constructor for full details.

While the ZipFile class is generally easier to use, this class provides an alternative to those applications that want to read from a zipfile directly, using a Stream.

Properties

CanRead

Always returns true.

public override bool CanRead { get; }

Property Value

bool

CanSeek

Returns the value of CanSeek for the underlying (wrapped) stream.

public override bool CanSeek { get; }

Property Value

bool

CanWrite

Always returns false.

public override bool CanWrite { get; }

Property Value

bool

CodecBufferSize

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

public int CodecBufferSize { get; set; }

Property Value

int

Remarks

Setting this affects the performance and memory efficiency of compression and decompression. For larger files, setting this to a larger size may improve performance, but the exact numbers vary depending on available memory, 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.

Length

Returns the length of the underlying stream.

public override long Length { get; }

Property Value

long

Password

Sets the password to be used on the ZipInputStream instance.

public string Password { set; }

Property Value

string

Examples

This example uses the ZipInputStream to read and extract entries from a zip file, using a potentially different password for each entry.

byte[] buffer= new byte[2048];
int n;
using (var raw = File.Open(_inputFileName, FileMode.Open, FileAccess.Read ))
{
    using (var input= new ZipInputStream(raw))
    {
        ZipEntry e;
        while (( e = input.GetNextEntry()) != null)
        {
            input.Password = PasswordForEntry(e.FileName);
            if (e.IsDirectory) continue;
            string outputPath = Path.Combine(_extractDir, e.FileName);
            using (var output = File.Open(outputPath, FileMode.Create, FileAccess.ReadWrite))
            {
                while ((n= input.Read(buffer,0,buffer.Length)) > 0)
                {
                    output.Write(buffer,0,n);
                }
            }
        }
    }
}

Remarks

When reading a zip archive, this password is used to read and decrypt the entries that are encrypted within the zip file. When entries within a zip file use different passwords, set the appropriate password for the entry before the first call to Read() for each entry.

When reading an entry that is not encrypted, the value of this property is ignored.

Position

Gets or sets the position of the underlying stream.

public override long Position { get; set; }

Property Value

long

Remarks

Setting the position is equivalent to calling Seek(value, SeekOrigin.Begin).

ProvisionalAlternateEncoding

The text encoding to use when reading entries into the zip archive, for those entries whose filenames or comments cannot be encoded with the default (IBM437) encoding.

public Encoding ProvisionalAlternateEncoding { get; set; }

Property Value

Encoding

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 read zip archives that use something other than UTF-8 or IBM437, set this property to specify the code page to use when reading encoded filenames and comments for each ZipEntry in the zip file.

This property is "provisional". When the entry in the zip archive is not explicitly marked as using UTF-8, then IBM437 is used to decode filenames and comments. If a loss of data would result from using IBM436 - specifically when encoding and decoding is not reflexive - the codepage specified here is used. It is possible, therefore, to have a given entry with a Comment encoded in IBM437 and a FileName encoded with the specified "provisional" codepage.

When a zip file uses an arbitrary, non-UTF8 code page for encoding, there is no standard way for the reader application - whether DotNetZip, WinZip, WinRar, or something else - to know which codepage has been used for the entries. 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. 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.

Methods

Dispose(bool)

Dispose the stream.

protected override void Dispose(bool disposing)

Parameters

disposing bool

true if the Dispose method was invoked by user code.

Remarks

This method disposes the ZipInputStream. It may also close the underlying stream, depending on which constructor was used.

Typically the application will call Dispose() implicitly, via a using statement in C#, or a Using statement in VB.

Application code won't call this code directly. This method may be invoked in two distinct scenarios. If disposing == true, the method has been called directly or indirectly by a user's code, for example via the public Dispose() method. In this case, both managed and unmanaged resources can be referenced and disposed. If disposing == false, the method has been called by the runtime from inside the object finalizer and this method should not reference other objects; in that case only unmanaged resources must be referenced or disposed.

Flush()

This is a no-op.

public override void Flush()

GetNextEntry()

Read the next entry from the zip file.

public ZipEntry GetNextEntry()

Returns

ZipEntry

The ZipEntry read. Returns null (or Nothing in VB) if there are no more entries in the zip file.

Remarks

Call this method just before calling Read(byte[], int, int), to position the pointer in the zip file to the next entry that can be read. Subsequent calls to Read(), will decrypt and decompress the data in the zip file, until Read() returns 0.

Each time you call GetNextEntry(), the pointer in the wrapped stream is moved to the next entry in the zip file. If you call Seek(long, SeekOrigin), and thus re-position the pointer within the file, you will need to call GetNextEntry() again, to insure that the file pointer is positioned at the beginning of a zip entry.

This method returns the ZipEntry. Using a stream approach, you will read the raw bytes for an entry in a zip file via calls to Read(). Alternatively, you can extract an entry into a file, or a stream, by calling Extract(), or one of its siblings.

Read(byte[], int, int)

Read the data from the stream into the buffer.

public override int Read(byte[] buffer, int offset, int count)

Parameters

buffer byte[]

The buffer to hold the data read from the stream.

offset int

the offset within the buffer to copy the first byte read.

count int

the number of bytes to read.

Returns

int

the number of bytes read, after decryption and decompression.

Remarks

The data for the zipentry will be decrypted and uncompressed, as necessary, before being copied into the buffer.

You must set the Password property before calling Read() the first time for an encrypted entry. To determine if an entry is encrypted and requires a password, check the ZipEntry.Encryption property.

Seek(long, SeekOrigin)

This method seeks in the underlying stream.

public override long Seek(long offset, SeekOrigin origin)

Parameters

offset long

the offset point to seek to

origin SeekOrigin

the reference point from which to seek

Returns

long

The new position

Remarks

Call this method if you want to seek around within the zip file for random access.

Applications can intermix calls to Seek() with calls to GetNextEntry(). After a call to Seek(), GetNextEntry() will get the next ZipEntry that falls after the current position in the input stream. You're on your own for finding out just where to seek in the stream, to get to the various entries.

SetLength(long)

This method always throws a NotSupportedException.

public override void SetLength(long value)

Parameters

value long

ignored

ToString()

Provides a string representation of the instance.

public override string ToString()

Returns

string

a string representation of the instance.

Remarks

This can be useful for debugging purposes.

Write(byte[], int, int)

This method always throws a NotSupportedException.

public override void Write(byte[] buffer, int offset, int count)

Parameters

buffer byte[]

ignored

offset int

ignored

count int

ignored