-
Notifications
You must be signed in to change notification settings - Fork 996
Zip Samples
Code Reference / Zip Samples
How to use SharpZipLib to work with Zip files
These samples try to cover the range of situations you will encounter. You may need to combine parts of each sample for your application.
Table of Contents on this page
Create a Zip with full control over content
Create a Zip from/to a memory stream or byte array
Create a Zip as a browser download attachment in IIS
Unpack a Zip with full control over the operation
Unpack a Zip - including embedded zips - and re-pack into a new zip or memorystream
Unpack a zip using ZipInputStream (eg for Unseekable input streams)
Download and Unpack a zip from an FTP server with recovery
This sample illustrates two major aspects:
- how to extract files from embedded zips (a zip within a zip).
- how to rebuild the contents into a new zip (optionally changing compression levels and changing encryption).
This example includes disk vs memorystream.
using ICSharpCode.SharpZipLib.Core;
using ICSharpCode.SharpZipLib.Zip;
private ZipOutputStream _zipOut;
private byte[] _buffer = new byte[4096];
// This example illustrates reading an input disk file (or any input stream),
// extracting the individual files, including from embedded zipfiles,
// and writing them to a new zipfile with an output memorystream or disk file.
//
public void DoRebuildFile(string zipFileIn, string password) {
Stream inStream = File.OpenRead(zipFileIn);
MemoryStream outputMemStream = new MemoryStream();
_zipOut = new ZipOutputStream(outputMemStream);
_zipOut.IsStreamOwner = false; // False stops the Close also Closing the underlying stream.
// To output to a disk file, replace the above with
//
// FileStream fsOut = File.Create(newZipFileName);
// _zipOut = new ZipOutputStream(fsOut);
// _zipOut.IsStreamOwner = true; // Makes the Close also Close the underlying stream.
_zipOut.SetLevel(3);
_zipOut.Password = password; // optional
RecursiveExtractRebuild(inStream);
inStream.Close();
// Must finish the ZipOutputStream to finalise output before using outputMemStream.
_zipOut.Close();
outputMemStream.Position = 0;
// At this point the underlying output memory stream (outputMemStream) contains the zip.
// If outputting to a web response, see the "Create a Zip as a browser download attachment in IIS" example above.
// See the "Create a Zip to a memory stream or byte array" example for other output options.
}
// Calls itself recursively if embedded zip
//
private void RecursiveExtractRebuild(Stream str) {
ZipFile zipFile = new ZipFile(str);
zipFile.IsStreamOwner = false;
foreach (ZipEntry zipEntry in zipFile) {
if (!zipEntry.IsFile)
continue;
String entryFileName = zipEntry.Name; // or Path.GetFileName(zipEntry.Name) to omit folder
// Specify any other filtering here.
Stream zipStream = zipFile.GetInputStream(zipEntry);
// Zips-within-zips are extracted. If you don't want this and wish to keep embedded zips as-is, just delete these 3 lines.
if (entryFileName.EndsWith(".zip", StringComparison.OrdinalIgnoreCase)) {
RecursiveExtractRebuild(zipStream);
} else {
ZipEntry newEntry = new ZipEntry(entryFileName);
newEntry.DateTime = zipEntry.DateTime;
newEntry.Size = zipEntry.Size;
// Setting the Size will allow the zip to be unpacked by XP's built-in extractor and other older code.
_zipOut.PutNextEntry(newEntry);
StreamUtils.Copy(zipStream, _zipOut, _buffer);
_zipOut.CloseEntry();
}
}
}
Imports ICSharpCode.SharpZipLib.Core
Imports ICSharpCode.SharpZipLib.Zip
Private _zipOut As ZipOutputStream
Private _buffer As Byte() = New Byte(4095) {}
' This example illustrates reading an input disk file (or any input stream),
' extracting the individual files, including from embedded zipfiles,
' and writing them to a new zipfile with an output memorystream or disk file.
'
Public Sub DoRebuildFile(zipFileIn As String, password As String)
Dim inStream As Stream = File.OpenRead(zipFileIn)
Dim outputMemStream As New MemoryStream()
_zipOut = New ZipOutputStream(outputMemStream)
_zipOut.IsStreamOwner = False ' False stops the Close also Closing the underlying stream.
' To output to a disk file, replace the above with
'
' FileStream fsOut = File.Create(newZipFileName);
' _zipOut = new ZipOutputStream(fsOut);
' _zipOut.IsStreamOwner = true; ' Makes the Close also Close the underlying stream.
_zipOut.SetLevel(3)
_zipOut.Password = password ' optional
RecursiveExtractRebuild(inStream)
inStream.Close()
' Must finish the ZipOutputStream to finalise output before using outputMemStream.
_zipOut.Close()
outputMemStream.Position = 0
' At this point the underlying output memory stream (outputMemStream) contains the zip.
' If outputting to a web response, see the "Create a Zip as a browser download attachment in IIS" example above.
' See the "Create a Zip to a memory stream or byte array" example for other output options.
End Sub
' Calls itself recursively if embedded zip
'
Private Sub RecursiveExtractRebuild(str As Stream)
Dim zipFile As New ZipFile(str)
zipFile.IsStreamOwner = False
For Each zipEntry As ZipEntry In zipFile
If Not zipEntry.IsFile Then
Continue For
End If
Dim entryFileName As [String] = zipEntry.Name ' or Path.GetFileName(zipEntry.Name) to omit folder
' Specify any other filtering here.
Dim zipStream As Stream = zipFile.GetInputStream(zipEntry)
' Zips-within-zips are extracted. If you don't want this and wish to keep embedded zips as-is, just delete these 3 lines.
If entryFileName.EndsWith(".zip", StringComparison.OrdinalIgnoreCase) Then
RecursiveExtractRebuild(zipStream)
Else
Dim newEntry As New ZipEntry(entryFileName)
newEntry.DateTime = zipEntry.DateTime
newEntry.Size = zipEntry.Size
' Setting the Size will allow the zip to be unpacked by XP's built-in extractor and other older code.
_zipOut.PutNextEntry(newEntry)
StreamUtils.Copy(zipStream, _zipOut, _buffer)
_zipOut.CloseEntry()
End If
Next
End Sub
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.
// Calling example:
WebClient webClient = new WebClient();
Stream data = 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) {
ZipInputStream zipInputStream = new ZipInputStream(zipStream);
ZipEntry zipEntry = zipInputStream.GetNextEntry();
while (zipEntry != null) {
String entryFileName = 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.
byte[] buffer = new byte[4096]; // 4K is optimum
// Manipulate the output filename here as desired.
String fullZipToPath = Path.Combine(outFolder, entryFileName);
string directoryName = Path.GetDirectoryName(fullZipToPath);
if (directoryName.Length > 0)
Directory.CreateDirectory(directoryName);
// Skip directory entry
string fileName = Path.GetFileName(fullZipToPath);
if (fileName.Length == 0)
{
zipEntry = zipInputStream.GetNextEntry();
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);
}
zipEntry = zipInputStream.GetNextEntry();
}
}
' 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
This example extends upon the previous, to provide for a recoverable FTP download and extract. Second draft.
public class FtpSample {
public static void TestZipDownload() {
// Create the FTP stream that takes care of restarting in event of failure.
// This will hide any temporary problems from ZipInputStream
//
Stream ftpStream = new FtpDownloadStream("ftp://www.contoso.com/test.htm", "anonymous", "[email protected]");
UnzipFromStream(ftpStream, @"c:\temp\out");
ftpStream.Close();
}
// Insert the "UnzipFromStream" code from the sample, above.
}
// Implements a restartable Ftp Download and exposes the result as an uninterrupted stream.
public class FtpDownloadStream : Stream {
private string _serverUri;
private string _userName;
private string _password;
private FtpWebRequest _request;
private FtpWebResponse _response;
private Stream _responseStream;
private int _totalDone;
public Exception CaughtException;
public FtpDownloadStream(string serverUri, string userName, string password) {
_serverUri = serverUri;
_userName = userName;
_password = password;
}
private void StartFtpDownload() {
// This can be replaced with the Http equivalents
_request = (FtpWebRequest)WebRequest.Create(_serverUri);
_request.Method = WebRequestMethods.Ftp.DownloadFile;
_request.Credentials = new NetworkCredential(_userName, _password);
_request.ContentOffset = _totalDone; // for resume on failure
_response = (FtpWebResponse)_request.GetResponse();
_responseStream = _response.GetResponseStream();
//if (_responseStream != null)
// _responseStream.ReadTimeout = 10000; // Set timeout to 10 seconds for testing.
}
public override int Read(byte[] buffer, int offset, int count) {
//
int attempts = 0;
while (attempts++ < 5) { // Adjust the maximum attempts according to your needs
if (_responseStream == null) {
StartFtpDownload();
}
try {
// This will throw a timeout exception if the connection is interrupted.
// Will throw null exception if failed to open (start); this will also retry.
int done = _responseStream.Read(buffer, offset, count);
_totalDone += done;
return done;
}
catch (Exception ex) {
CaughtException = ex;
// Close ftp resources if possible. Set instances to null to force restart.
Close();
}
}
return 0;
}
public override void Close() {
if (_responseStream != null) {
try {
_responseStream.Close();
_response.Close();
}
catch {
// No action required
}
}
_responseStream = null;
_response = null;
_request = null;
}
// Implement the Stream methods
public override void Flush() {
throw new NotImplementedException();
}
public override long Seek(long offset, SeekOrigin origin) {
throw new NotImplementedException();
}
public override void SetLength(long value) {
throw new NotImplementedException();
}
public override void Write(byte[] buffer, int offset, int count) {
throw new NotImplementedException();
}
public override bool CanRead {
get { return true; }
}
public override bool CanSeek {
get { return false; }
}
public override bool CanWrite {
get { return false; }
}
public override long Length {
get { throw new NotImplementedException(); }
}
public override long Position {
get { throw new NotImplementedException(); }
set { throw new NotImplementedException(); }
}
}