Unpack a Zip, including embedded zips, and re pack into a new zip or memorystream - icsharpcode/SharpZipLib GitHub Wiki
Code Reference / Zip Samples / Unpack a Zip, including embedded zips, and re-pack into a new zip or memorystream
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.
C#
using ICSharpCode.SharpZipLib.Core;
using ICSharpCode.SharpZipLib.Zip;
// 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) {
using(var outputStream = new MemoryStream())
// To output to a disk file, replace the above with
//using(var outputStream = File.Create(newZipFileName);
using(var zipOutStream = new ZipOutputStream(outputStream))
{
// Stops the Close also Closing the underlying stream.
zipOutStream.IsStreamOwner = false;
zipOutStream.SetLevel(3);
// Optionally set password
zipOutStream.Password = password;
using(var inStream = File.OpenRead(zipFileIn))
{
RecursiveExtractRebuild(zipOutStream, inStream);
}
}
// At this point the underlying output memory stream (outputStream) contains the zip.
// If outputting to a web response, see the "Create a Zip as a browser download attachment in IIS"
// See the "Create a Zip to a memory stream or byte array" example for other output options.
}
// Recursively extract embedded zip files
private void RecursiveExtractRebuild(ZipOutputStream outZipStream, Stream inStream)
{
var buffer = new byte[4096];
using(var zipFile = new ZipFile(inStream, leaveOpen: true))
{
foreach (ZipEntry zipEntry in zipFile)
{
if (!zipEntry.IsFile)
continue;
// To omit folder use:
//var entryFileName = Path.GetFileName(zipEntry.Name)
var entryFileName = zipEntry.Name;
// Specify any other filtering here.
using(var zipStream = zipFile.GetInputStream(zipEntry))
{
// Extract Zips-within-zips
if (entryFileName.EndsWith(".zip", StringComparison.OrdinalIgnoreCase))
{
RecursiveExtractRebuild(outZipStream, zipStream);
}
else
{
outZipStream.PutNextEntry(new ZipEntry(entryFileName)
{
DateTime = zipEntry.DateTime,
Size = zipEntry.Size,
});
StreamUtils.Copy(zipStream, outZipStream, buffer);
outZipStream.CloseEntry();
}
}
}
}
}
Visual Basic
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