SharZipLib 例子

来源:互联网 发布:暖气片造价知乎 编辑:程序博客网 时间:2024/05/19 06:36

http://wiki.sharpdevelop.net/SharpZipLib-Zip-Samples.ashx


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 [Hide/Show]


Create a Zip with full control over contents
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)


Create a Zip with full control over contents¶

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.

C#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) {FileStream fsOut = File.Create(outPathname);ZipOutputStream zipStream = new ZipOutputStream(fsOut);zipStream.SetLevel(3); //0-9, 9 being the highest level of compressionzipStream.Password = password;// optional. Null is the same as not setting.// 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 folderOffset = 0.int folderOffset = folderName.Length + (folderName.EndsWith("\\") ? 0 : 1);CompressFolder(folderName, zipStream, folderOffset);zipStream.IsStreamOwner = true;// Makes the Close also Close the underlying streamzipStream.Close();}// Recurses down the folder structure//private void CompressFolder(string path, ZipOutputStream zipStream, int folderOffset) {string[] files = Directory.GetFiles(path);foreach (string filename in files) {FileInfo fi = new FileInfo(filename);string entryName = filename.Substring(folderOffset); // Makes the name in zip based on the folderentryName = ZipEntry.CleanName(entryName); // Removes drive from name and fixes slash directionZipEntry newEntry = new ZipEntry(entryName);newEntry.DateTime = fi.LastWriteTime; // Note the zip format stores 2 second granularity// 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 occursbyte[ ] buffer = new byte[4096];using (FileStream streamReader = File.OpenRead(filename)) {StreamUtils.Copy(streamReader, zipStream, buffer);}zipStream.CloseEntry();}string[ ] folders = Directory.GetDirectories(path);foreach (string folder in folders) {CompressFolder(folder, zipStream, folderOffset);}}

VBImports SystemImports System.IOImports ICSharpCode.SharpZipLib.CoreImports 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)Dim fsOut As FileStream = File.Create(outPathname)Dim zipStream As New ZipOutputStream(fsOut)zipStream.SetLevel(3)'0-9, 9 being the highest level of compressionzipStream.Password = password' optional. Null is the same as not setting.' 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 folderOffset = 0.Dim folderOffset As Integer = folderName.Length + (If(folderName.EndsWith("\"), 0, 1))CompressFolder(folderName, zipStream, folderOffset)zipStream.IsStreamOwner = True' Makes the Close also Close the underlying streamzipStream.Close()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 filesDim fi As New FileInfo(filename)Dim entryName As String = filename.Substring(folderOffset)' Makes the name in zip based on the folderentryName = ZipEntry.CleanName(entryName)' Removes drive from name and fixes slash directionDim newEntry As New ZipEntry(entryName)newEntry.DateTime = fi.LastWriteTime' Note the zip format stores 2 second granularity' 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.LengthzipStream.PutNextEntry(newEntry)' Zip the file in buffered chunks' the "using" will close the stream even if an exception occursDim buffer As Byte() = New Byte(4095) {}Using streamReader As FileStream = File.OpenRead(filename)StreamUtils.Copy(streamReader, zipStream, buffer)End UsingzipStream.CloseEntry()NextDim folders As String() = Directory.GetDirectories(path)For Each folder As String In foldersCompressFolder(folder, zipStream, folderOffset)NextEnd Sub

Create a Zip from/to a memory stream or byte array¶

This sample concentrates on the differences for memorystream output, the most important of which is setting IsStreamOwner = false so that the Close (which is needed to finish up the output) does not close the underlying memorystream.For multiple entries, passwords, etc, see the code sample above.

C#using ICSharpCode.SharpZipLib.Zip;// Compresses the supplied memory stream, naming it as zipEntryName, into a zip,// which is returned as a memory stream or a byte array.//public MemoryStream CreateToMemoryStream(MemoryStream memStreamIn, string zipEntryName) {MemoryStream outputMemStream = new MemoryStream();ZipOutputStream zipStream = new ZipOutputStream(outputMemStream);zipStream.SetLevel(3); //0-9, 9 being the highest level of compressionZipEntry newEntry = new ZipEntry(zipEntryName);newEntry.DateTime = DateTime.Now;zipStream.PutNextEntry(newEntry);StreamUtils.Copy(memStreamIn, zipStream, new byte[4096]);zipStream.CloseEntry();zipStream.IsStreamOwner = false;// False stops the Close also Closing the underlying stream.zipStream.Close();// Must finish the ZipOutputStream before using outputMemStream.outputMemStream.Position = 0;return outputMemStream;// Alternative outputs:// ToArray is the cleaner and easiest to use correctly with the penalty of duplicating allocated memory.byte[] byteArrayOut = outputMemStream.ToArray();// GetBuffer returns a raw buffer raw and so you need to account for the true length yourself.byte[] byteArrayOut = outputMemStream.GetBuffer();long len = outputMemStream.Length;}

VBImports ICSharpCode.SharpZipLib.Zip' Compresses the supplied memory stream, naming it as zipEntryName, into a zip,' which is returned as a memory stream or a byte array.'Public Function CreateToMemoryStream(memStreamIn As MemoryStream, zipEntryName As String) As MemoryStreamDim outputMemStream As New MemoryStream()Dim zipStream As New ZipOutputStream(outputMemStream)zipStream.SetLevel(3)'0-9, 9 being the highest level of compressionDim newEntry As New ZipEntry(zipEntryName)newEntry.DateTime = DateTime.NowzipStream.PutNextEntry(newEntry)StreamUtils.Copy(memStreamIn, zipStream, New Byte(4095) {})zipStream.CloseEntry()zipStream.IsStreamOwner = False' False stops the Close also Closing the underlying stream.zipStream.Close()' Must finish the ZipOutputStream before using outputMemStream.outputMemStream.Position = 0Return outputMemStream' Alternative outputs:' ToArray is the cleaner and easiest to use correctly with the penalty of duplicating allocated memory.Dim byteArrayOut As Byte() = outputMemStream.ToArray()' GetBuffer returns a raw buffer raw and so you need to account for the true length yourself.Dim byteArrayOut As Byte() = outputMemStream.GetBuffer()Dim len As Long = outputMemStream.LengthEnd Function

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-dispositionbyte[] buffer = new byte[4096];ZipOutputStream zipOutputStream = new ZipOutputStream(Response.OutputStream);zipOutputStream.SetLevel(3); //0-9, 9 being the highest level of compressionforeach (string fileName in zipFileList) {Stream fs = File.OpenRead(fileName);// or any suitable inputstreamZipEntry 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 set zipOutputStream.UseZip64 = UseZip64.Off instead.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();}fs.Close();}zipOutputStream.Close();Response.Flush();Response.End();}

VB' 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-dispositionDim buffer As Byte() = New Byte(4095) {}Dim zipOutputStream As New ZipOutputStream(Response.OutputStream)zipOutputStream.SetLevel(3)'0-9, 9 being the highest level of compressionFor Each fileName As String In zipFileListDim fs As Stream = File.OpenRead(fileName)' or any suitable inputstreamDim 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 > 0zipOutputStream.Write(buffer, 0, count)count = fs.Read(buffer, 0, buffer.Length)If Not Response.IsClientConnected ThenExit WhileEnd IfResponse.Flush()End Whilefs.Close()NextzipOutputStream.Close()Response.Flush()Response.End()End Sub

Unpack a Zip with full control over the operation¶

This sample illustrates many aspects:
  • skipping directory entries
  • controlling the folder where the output is placed
  • passwords
  • exception handling, closing disk files, and efficient use of memory.

While this example is purely disk files, scroll down where other inputs and outputs such as memory stream are covered.

C#using ICSharpCode.SharpZipLib.Core;using ICSharpCode.SharpZipLib.Zip;public void ExtractZipFile(string archiveFilenameIn, string password, string outFolder) {ZipFile zf = null;try {FileStream fs = File.OpenRead(archiveFilenameIn);zf = new ZipFile(fs);if (!String.IsNullOrEmpty(password)) {zf.Password = password;// AES encrypted entries are handled automatically}foreach (ZipEntry zipEntry in zf) {if (!zipEntry.IsFile) {continue;// Ignore directories}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 optimumStream zipStream = zf.GetInputStream(zipEntry);// 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);// 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(zipStream, streamWriter, buffer);}}} finally {if (zf != null) {zf.IsStreamOwner = true; // Makes close also shut the underlying streamzf.Close(); // Ensure we release resources}}}

VBImports ICSharpCode.SharpZipLib.CoreImports ICSharpCode.SharpZipLib.ZipPublic Sub ExtractZipFile(archiveFilenameIn As String, password As String, outFolder As String)Dim zf As ZipFile = NothingTryDim fs As FileStream = File.OpenRead(archiveFilenameIn)zf = New ZipFile(fs)If Not [String].IsNullOrEmpty(password) Then' AES encrypted entries are handled automaticallyzf.Password = passwordEnd IfFor Each zipEntry As ZipEntry In zfIf Not zipEntry.IsFile Then' Ignore directoriesContinue ForEnd IfDim 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 optimumDim zipStream As Stream = zf.GetInputStream(zipEntry)' 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 ThenDirectory.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(zipStream, streamWriter, buffer)End UsingNextFinallyIf zf IsNot Nothing Thenzf.IsStreamOwner = True' Makes close also shut the underlying stream' Ensure we release resourceszf.Close()End IfEnd TryEnd Sub



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;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;// optionalRecursiveExtractRebuild(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();}}}

VBImports ICSharpCode.SharpZipLib.CoreImports ICSharpCode.SharpZipLib.ZipPrivate _zipOut As ZipOutputStreamPrivate _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' optionalRecursiveExtractRebuild(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 = FalseFor Each zipEntry As ZipEntry In zipFileIf Not zipEntry.IsFile ThenContinue ForEnd IfDim 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) ThenRecursiveExtractRebuild(zipStream)ElseDim newEntry As New ZipEntry(entryFileName)newEntry.DateTime = zipEntry.DateTimenewEntry.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 IfNextEnd Sub



Unpack a zip using ZipInputStream (eg for Unseekable input streams)¶

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: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.GetViaZipInput(data, @"c:\temp");public void GetViaZipInput(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);// 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();}}

VB' 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.GetViaZipInput(data, "c:\temp")Public Sub GetViaZipInput(zipStream As Stream, outFolder As String)Dim zipInputStream As New ZipInputStream(zipStream)Dim zipEntry As ZipEntry = zipInputStream.GetNextEntry()While zipEntry IsNot NothingDim 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 ThenDirectory.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 UsingzipEntry = zipInputStream.GetNextEntry()End WhileEnd Sub