Skip to content

Create a Zip as a browser download attachment in IIS

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

Code Reference / Zip Samples / Create a Zip as a browser download attachment in IIS

This sample creates a zip as a browser download.

By writing directly to the Response OutputStream, zip download starts immediately, which fixes timeout problems when zipping large files.

For inputting from a memorystream instead of disk files, or passwording etc, see the samples above.

C#

// the aspx page has just one line e.g. <%@ Page language="c#" Codebehind=...
// but if you must run this from within a page that has other output, start
// with a Response.Clear();

using ICSharpCode.SharpZipLib.Zip;

// This will accumulate each of the files named in the fileList into a zip file,
// and stream it to the browser.
// This approach writes directly to the Response OutputStream.
// The browser starts to receive data immediately which should avoid 
// timeout problems.
// This also avoids an intermediate memorystream, saving memory on large files.
private void DownloadZipToBrowser(List <string> zipFileList) {

    Response.ContentType = "application/zip";
    // If the browser is receiving a mangled zipfile, IIS Compression may cause
    // this problem. Some members have found that 
    //Response.ContentType = "application/octet-stream" 
    // has solved this. May be specific to Internet Explorer.

    Response.AppendHeader("Content-Disposition", 
        "attachment; filename=\"Download.zip\"");
    Response.CacheControl = "Private";

    Response.Cache.SetExpires(DateTime.Now.AddMinutes(3));
    // or put a timestamp in the filename in the content-disposition

    var buffer = new byte[4096];

    using(var zipOutputStream = new ZipOutputStream(Response.OutputStream)){

        // 0-9, 9 being the highest level of compression
        zipOutputStream.SetLevel(3);

        foreach (string fileName in zipFileList) {

            using(Stream fs = File.OpenRead(fileName)) {

                var entry = new ZipEntry(ZipEntry.CleanName(fileName));
                entry.Size = fs.Length;
                // Setting the Size provides WinXP built-in extractor 
                // compatibility, but if not available, you can instead set 
                //zipOutputStream.UseZip64 = UseZip64.Off

                zipOutputStream.PutNextEntry(entry);

                int count = fs.Read(buffer, 0, buffer.Length);
                while (count > 0) {
                    zipOutputStream.Write(buffer, 0, count);
                    count = fs.Read(buffer, 0, buffer.Length);
                    if (!Response.IsClientConnected) {
                        break;
                    }
                    Response.Flush();
                }
            }
        }
    }

    Response.Flush();
    Response.End();
}

Visual Basic

' the aspx page has just one line e.g. <%@ Page language="vb" Codebehind=...
' but if you must run this from within a page that has other output, start with a Response.Clear()

Imports ICSharpCode.SharpZipLib.Zip

' This will accumulate each of the files named in the fileList into a zip file,
' and stream it to the browser.
' This approach writes directly to the Response OutputStream.
' The browser starts to receive data immediately which should avoid timeout problems.
' This also avoids an intermediate memorystream, saving memory on large files.
'
Private Sub DownloadZipToBrowser(zipFileList As List(Of String))

    Response.ContentType = "application/zip"
    ' If the browser is receiving a mangled zipfile, IIS Compression may cause this problem. Some members have found that
    'Response.ContentType = "application/octet-stream" has solved this. May be specific to Internet Explorer.

    Response.AppendHeader("content-disposition", "attachment; filename=""Download.zip""")
    response.CacheControl = "Private"
    response.Cache.SetExpires(DateTime.Now.AddMinutes(3))
    ' or put a timestamp in the filename in the content-disposition
    Dim buffer As Byte() = New Byte(4095) {}

    Dim zipOutputStream As New ZipOutputStream(Response.OutputStream)
    zipOutputStream.SetLevel(3)		'0-9, 9 being the highest level of compression
    For Each fileName As String In zipFileList

        Dim fs As Stream = File.OpenRead(fileName)
        ' or any suitable inputstream
        Dim entry As New ZipEntry(ZipEntry.CleanName(fileName))
        entry.Size = fs.Length
        ' Setting the Size provides WinXP built-in extractor compatibility,
        '  but if not available, you can set zipOutputStream.UseZip64 = UseZip64.Off instead.

        zipOutputStream.PutNextEntry(entry)

        Dim count As Integer = fs.Read(buffer, 0, buffer.Length)
        While count > 0
            zipOutputStream.Write(buffer, 0, count)
            count = fs.Read(buffer, 0, buffer.Length)
            If Not Response.IsClientConnected Then
                Exit While
            End If
            Response.Flush()
        End While
        fs.Close()
    Next
    zipOutputStream.Close()

    Response.Flush()
    Response.End()
End Sub