Skip to content

Create a Zip with full control over content

Rami edited this page Apr 3, 2020 · 3 revisions

Code Reference / Zip Samples / Create a Zip with full control over content

This sample illustrates many aspects:

  • multiple entries
  • entry name correction
  • passwords and encryption options
  • Zip64 format issues.

While this example is purely disk files, the next following example shows how to use memory stream for input and output.

using System;
using System.IO;
using ICSharpCode.SharpZipLib.Core;
using ICSharpCode.SharpZipLib.Zip;

// Compresses the files in the nominated folder, and creates a zip file 
// on disk named as outPathname.
public void CreateSample(string outPathname, string password, string folderName) {

    using(FileStream fsOut = File.Create(outPathname))
    using(var zipStream = new ZipOutputStream(fsOut)) {

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

        // optional. Null is the same as not setting. Required if using AES.
        zipStream.Password = password;	

        // This setting will strip the leading part of the folder path in the entries, 
        // to make the entries relative to the starting folder.
        // To include the full path for each entry up to the drive root, assign to 0.
        int folderOffset = folderName.Length + (folderName.EndsWith("\\") ? 0 : 1);

        CompressFolder(folderName, zipStream, folderOffset);

    }

}

// Recursively compresses a folder structure
private void CompressFolder(string path, ZipOutputStream zipStream, int folderOffset) {

    var files = Directory.GetFiles(path);

    foreach (var filename in files) {

        var fi = new FileInfo(filename);

        // Make the name in zip based on the folder
        var entryName = filename.Substring(folderOffset);

        // Remove drive from name and fix slash direction
        entryName = ZipEntry.CleanName(entryName); 

        var newEntry = new ZipEntry(entryName);

        // Note the zip format stores 2 second granularity
        newEntry.DateTime = fi.LastWriteTime; 

        // Specifying the AESKeySize triggers AES encryption. 
        // Allowable values are 0 (off), 128 or 256.
        // A password on the ZipOutputStream is required if using AES.
        //   newEntry.AESKeySize = 256;

        // To permit the zip to be unpacked by built-in extractor in WinXP and Server2003,
        // WinZip 8, Java, and other older code, you need to do one of the following: 
        // Specify UseZip64.Off, or set the Size.
        // If the file may be bigger than 4GB, or you do not need WinXP built-in compatibility, 
        // you do not need either, but the zip will be in Zip64 format which
        // not all utilities can understand.
        //   zipStream.UseZip64 = UseZip64.Off;
        newEntry.Size = fi.Length;

        zipStream.PutNextEntry(newEntry);

        // Zip the file in buffered chunks
        // the "using" will close the stream even if an exception occurs
        var buffer = new byte[4096];
        using (FileStream fsInput = File.OpenRead(filename)) {
            StreamUtils.Copy(fsInput, zipStream, buffer);
        }
        zipStream.CloseEntry();
    }

    // Recursively call CompressFolder on all folders in path
    var folders = Directory.GetDirectories(path);
    foreach (var folder in folders) {
        CompressFolder(folder, zipStream, folderOffset);
    }
}
Imports System
Imports System.IO
Imports ICSharpCode.SharpZipLib.Core
Imports ICSharpCode.SharpZipLib.Zip

' Compresses the files in the nominated folder, and creates a zip file on disk named as outPathname.
'
Public Sub CreateSample(outPathname As String, password As String, folderName As String)

    Using fsOut As FileStream = File.Create(outPathname)
        Using zipStream As New ZipOutputStream(fsOut)

            '0-9, 9 being the highest level of compression
            zipStream.SetLevel(3)

            ' optional. Null is the same as not setting.
            zipStream.Password = password	

            ' This setting will strip the leading part of the folder path in the entries, 
            ' to make the entries relative to the starting folder.
            ' To include the full path for each entry up to the drive root, assign to 0.
            Dim folderOffset As Integer = folderName.Length + (If(folderName.EndsWith("\"), 0, 1))

            CompressFolder(folderName, zipStream, folderOffset)

        End Using
    End Using
End Sub

' Recurses down the folder structure
'
Private Sub CompressFolder(path As String, zipStream As ZipOutputStream, folderOffset As Integer)

    Dim files As String() = Directory.GetFiles(path)

    For Each filename As String In files

        Dim fi As New FileInfo(filename)

        ' Make the name in zip based on the folder
        Dim entryName As String = filename.Substring(folderOffset)
        
        ' Remove drive from name and fix slash direction
        entryName = ZipEntry.CleanName(entryName)
        Dim newEntry As New ZipEntry(entryName)
        
        ' Note the zip format stores 2 second granularity
        newEntry.DateTime = fi.LastWriteTime

        ' Specifying the AESKeySize triggers AES encryption. Allowable values are 0 (off), 128 or 256.
        '   newEntry.AESKeySize = 256;

        ' To permit the zip to be unpacked by built-in extractor in WinXP and Server2003, WinZip 8, Java, and other older code,
        ' you need to do one of the following: Specify UseZip64.Off, or set the Size.
        ' If the file may be bigger than 4GB, or you do not need WinXP built-in compatibility, you do not need either,
        ' but the zip will be in Zip64 format which not all utilities can understand.
        '   zipStream.UseZip64 = UseZip64.Off;
        newEntry.Size = fi.Length

        zipStream.PutNextEntry(newEntry)

        ' Zip the file in buffered chunks
        ' the "using" will close the stream even if an exception occurs
        Dim buffer As Byte() = New Byte(4095) {}
        Using streamReader As FileStream = File.OpenRead(filename)
            StreamUtils.Copy(streamReader, zipStream, buffer)
        End Using
        zipStream.CloseEntry()
    Next
    Dim folders As String() = Directory.GetDirectories(path)
    For Each folder As String In folders
        CompressFolder(folder, zipStream, folderOffset)
    Next
End Sub