Skip to content

Unpack a zip using ZipInputStream

nils måsén edited this page Aug 21, 2019 · 2 revisions

Code Reference / Zip Samples / Unpack a zip using ZipInputStream

The ZipInputStream has one major advantage over using ZipFile to read a zip: it can read from an unseekable input stream - such as a WebClient download. However it currently cannot decode AES encrypted zips.

C#

// Calling example:
using(var data = new WebClient().OpenRead("http://www.example.com/test.zip")){
    // This stream cannot be opened with the ZipFile class because CanSeek is false.
    UnzipFromStream(data, @"c:\temp");
}

public void UnzipFromStream(Stream zipStream, string outFolder)
{
    using(var zipInputStream = new ZipInputStream(zipStream))
    {
        while (zipInputStream.GetNextEntry() is ZipEntry zipEntry)
        {
            var entryFileName = zipEntry.Name;
            // To remove the folder from the entry:
            //var entryFileName = Path.GetFileName(entryFileName);
            // Optionally match entrynames against a selection list here
            // to skip as desired.
            // The unpacked length is available in the zipEntry.Size property.

            // 4K is optimum
            var buffer = new byte[4096];

            // Manipulate the output filename here as desired.
            var fullZipToPath = Path.Combine(outFolder, entryFileName);
            var directoryName = Path.GetDirectoryName(fullZipToPath);
            if (directoryName.Length > 0)
                Directory.CreateDirectory(directoryName);

            // Skip directory entry
            if (Path.GetFileName(fullZipToPath).Length == 0)
            {
                continue;
            }

            // Unzip file in buffered chunks. This is just as fast as unpacking
            // to a buffer the full size of the file, but does not waste memory.
            // The "using" will close the stream even if an exception occurs.
            using (FileStream streamWriter = File.Create(fullZipToPath))
            {
                StreamUtils.Copy(zipInputStream, streamWriter, buffer);
            }
        }
    }
}

Visual Basic

' Calling example:
    Dim webClient As new WebClient()
    Dim data As Stream = webClient.OpenRead("http://www.example.com/test.zip")
    ' This stream cannot be opened with the ZipFile class because CanSeek is false.
    UnzipFromStream(data, "c:\temp")

Public Sub UnzipFromStream(zipStream As Stream, outFolder As String)

    Dim zipInputStream As New ZipInputStream(zipStream)
    Dim zipEntry As ZipEntry = zipInputStream.GetNextEntry()
    While zipEntry IsNot Nothing
        Dim entryFileName As [String] = zipEntry.Name
        ' to remove the folder from the entry:- entryFileName = Path.GetFileName(entryFileName);
        ' Optionally match entrynames against a selection list here to skip as desired.
        ' The unpacked length is available in the zipEntry.Size property.

        Dim buffer As Byte() = New Byte(4095) {}	' 4K is optimum

        ' Manipulate the output filename here as desired.
        Dim fullZipToPath As [String] = Path.Combine(outFolder, entryFileName)
        Dim directoryName As String = Path.GetDirectoryName(fullZipToPath)
        If directoryName.Length > 0 Then
            Directory.CreateDirectory(directoryName)
        End If

        ' Unzip file in buffered chunks. This is just as fast as unpacking to a buffer the full size
        ' of the file, but does not waste memory.
        ' The "using" will close the stream even if an exception occurs.
        Using streamWriter As FileStream = File.Create(fullZipToPath)
            StreamUtils.Copy(zipInputStream, streamWriter, buffer)
        End Using
        zipEntry = zipInputStream.GetNextEntry()
    End While
End Sub