用.Net实现Zip
michael_wp原创
Michael_Jackson
头衔:我哪里有呀!:)
等级:小飞侠
财产:12660
经验:10258
魅力:3135
注册:2002-10-17
登录:2003-4-16
文章:462
签定:★不明32★
发贴时间: 2002-11-4 10:01:30
//ZipEntry.cs
using System;
using System.IO;
namespace OrganicBit.Zip
{
/// <summary>Specifies how the the zip entry should be compressed.</summary>
public enum CompressionMethod
{
/// <summary>No compression.</summary>
Stored = 0,
/// <summary>Default and only supported compression method.</summary>
Deflated = 8
}
/// <summary>Specifies the amount of compression to apply to compressed zip entires.</summary>
public enum CompressionLevel : int
{
/// <summary>Default compression level. A good choice for speed and size.</summary>
Default = -1,
/// <summary>Do not perfrom compression.</summary>
None = 0,
/// <summary>Compress the entry as fast as possible size trading size for time.</summary>
Fastest = 1,
/// <summary>Compress the entry using a balance of size and time.</summary>
Average = 5,
/// <summary>Compress the entry to smallest possible size trading time for size.</summary>
Smallest = 9
}
/// <summary>Represents a entry in a zip file.</summary>
public class ZipEntry
{
string _name = String.Empty;
uint _crc = 0;
long _compressedLength = -1;
long _uncompressedLength = -1;
byte[] _extraField = null;
string _comment = String.Empty;
DateTime _modifiedTime = DateTime.Now;
CompressionMethod _method = CompressionMethod.Deflated;
int _level = (int)CompressionLevel.Default;
/// <summary>Initializes a instance of the <see cref="ZipEntry"/> class with the given name.</summary>
/// <param name="name">The name of entry that will be stored in the directory of the zip file.</param>
public ZipEntry(string name)
{
Name = name;
}
/// <summary>Creates a new Zip file entry reading values from a zip file.</summary>
internal ZipEntry(IntPtr handle)
{
ZipEntryInfo entryInfo;
int result = 0;
unsafe
{
result = ZipLib.unzGetCurrentFileInfo(handle, &entryInfo, null, 0, null, 0, null, 0);
}
if (result != 0)
{
throw new ZipException("Could not read entries from zip file " + Name);
}
ExtraField = new byte[entryInfo.ExtraFieldLength];
sbyte[] entryNameBuffer = new sbyte[entryInfo.FileNameLength];
sbyte[] commentBuffer = new sbyte[entryInfo.CommentLength];
unsafe
{
result = ZipLib.unzGetCurrentFileInfo(handle, &entryInfo,
entryNameBuffer, (uint)entryNameBuffer.Length,
ExtraField, (uint)ExtraField.Length,
commentBuffer, (uint)commentBuffer.Length);
}
if (result != 0)
{
throw new ZipException("Could not read entries from zip file " + Name);
}
_name = ZipLib.AnsiToString(entryNameBuffer);
_comment = ZipLib.AnsiToString(commentBuffer);
_crc = entryInfo.Crc;
_compressedLength = entryInfo.CompressedSize;
_uncompressedLength = entryInfo.UncompressedSize;
_method = (CompressionMethod)entryInfo.CompressionMethod;
_modifiedTime = new DateTime(
(int)entryInfo.DateTime.Year,
(int)entryInfo.DateTime.Month + 1,
(int)entryInfo.DateTime.Day,
(int)entryInfo.DateTime.Hours,
(int)entryInfo.DateTime.Minutes,
(int)entryInfo.DateTime.Seconds);
}
/// <summary>Gets and sets the local file comment for the entry.</summary>
/// <remarks>
/// <para>Currently only Ascii 8 bit characters are supported in comments.</para>
/// <para>A comment cannot exceed 65535 bytes.</para>
/// </remarks>
public string Comment
{
get { return _comment; }
set
{
// null comments are valid
if (value != null)
{
if (value.Length > 0xffff)
{
throw new ArgumentOutOfRangeException("Comment cannot not exceed 65535 characters.");
}
if (!IsAscii(value))
{
throw new ArgumentException("Name can only contain Ascii 8 bit characters.");
}
}
// TODO: check for ASCII only characters
_comment = value;
}
}
/// <summary>Gets the compressed size of the entry data in bytes, or -1 if not known.</summary>
public long CompressedLength
{
get { return _compressedLength; }
}
/// <summary>Gets the CRC-32 checksum of the uncompressed entry data.</summary>
public uint Crc
{
get { return _crc; }
}
/// <summary>Gets and sets the optional extra field data for the entry.</summary>
/// <remarks>ExtraField data cannot exceed 65535 bytes.</remarks>
public byte[] ExtraField
{
get
{
return _extraField;
}
set
{
if (value.Length > 0xffff)
{
throw new ArgumentOutOfRangeException("ExtraField cannot not exceed 65535 bytes.");
}
_extraField = value;
}
}
/// <summary>Gets and sets the default compresion method for zip file entries. See <see cref="CompressionMethod"/> for a list of possible values.</summary>
public CompressionMethod Method
{
get { return _method; }
set { _method = value; }
}
/// <summary>Gets and sets the default compresion level for zip file entries. See <see cref="CompressionMethod"/> for a partial list of values.</summary>
public int Level
{
get { return _level; }
set
{
if (value < -1 || value > 9)
{
throw new ArgumentOutOfRangeException("Level", value, "Level value must be between -1 and 9.");
}
_level = value;
}
}
/// <summary>Gets the size of the uncompressed entry data in in bytes.</summary>
public long Length
{
get { return _uncompressedLength; }
}
/// <summary>Gets and sets the modification time of the entry.</summary>
public DateTime ModifiedTime
{
get { return _modifiedTime; }
set { _modifiedTime = value; }
}
/// <summary>Gets and sets the name of the entry.</summary>
/// <remarks>
/// <para>Currently only Ascii 8 bit characters are supported in comments.</para>
/// <para>A comment cannot exceed 65535 bytes.</para>
/// </remarks>
public string Name
{
get { return _name; }
set
{
if (value == null)
{
throw new ArgumentNullException("Name cannot be null.");
}
if (value.Length > 0xffff)
{
throw new ArgumentOutOfRangeException("Name cannot not exceed 65535 characters.");
}
if (!IsAscii(value))
{
throw new ArgumentException("Name can only contain Ascii 8 bit characters.");
}
// TODO: check for ASCII only characters
_name = value;
}
}
/// <summary>Flag that indicates if this entry is a directory or a file.</summary>
public bool IsDirectory
{
get
{
return (Length == 0 && CompressedLength == 0);
}
}
/// <summary>Gets the compression ratio as a percentage.</summary>
/// <remarks>Returns -1.0 if unknown.</remarks>
public float Ratio
{
get
{
float ratio = -1.0f;
if (Length > 0)
{
ratio = Convert.ToSingle(Length - CompressedLength) / Length;
}
return ratio;
}
}
/// <summary>Returns a string representation of the Zip entry.</summary>
public override string ToString()
{
return String.Format("{0} {1}", Name, base.ToString());
}
/// <summary>Check if <paramref name="str"/> only contains Ascii 8 bit characters.</summary>
static bool IsAscii(string str)
{
foreach (char ch in str)
{
if (ch > 0xff)
{
return false;
}
}
return true;
}
}
}
======================================================================
//ZipEntryCollection.cs
using System;
using System.Collections;
namespace OrganicBit.Zip
{
/// <summary>A collection that stores <see cref='OrganicBit.Zip.ZipEntry'/> objects.</summary>
/// <seealso cref='OrganicBit.Zip.ZipEntryCollection'/>
[Serializable()]
public class ZipEntryCollection : CollectionBase
{
/// <summary>Initializes a new instance of <see cref='OrganicBit.Zip.ZipEntryCollection'/>.</summary>
public ZipEntryCollection()
{
}
/// <summary>Initializes a new instance of <see cref='OrganicBit.Zip.ZipEntryCollection'/> based on another <see cref='OrganicBit.Zip.ZipEntryCollection'/>.</summary>
/// <param name='value'>A <see cref='OrganicBit.Zip.ZipEntryCollection'/> from which the contents are copied.</param>
public ZipEntryCollection(ZipEntryCollection value)
{
this.AddRange(value);
}
/// <summary>Initializes a new instance of <see cref='OrganicBit.Zip.ZipEntryCollection'/> containing any array of <see cref='OrganicBit.Zip.ZipEntry'/> objects.</summary>
/// <param name='value'>A array of <see cref='OrganicBit.Zip.ZipEntry'/> objects with which to intialize the collection.</param>
public ZipEntryCollection(ZipEntry[] value)
{
this.AddRange(value);
}
/// <summary>Represents the entry at the specified index of the <see cref='OrganicBit.Zip.ZipEntry'/>.</summary>
/// <param name='index'><para>The zero-based index of the entry to locate in the collection.</para></param>
/// <value>
/// <para>The entry at the specified index of the collection.</para>
/// </value>
/// <exception cref='System.ArgumentOutOfRangeException'><paramref name='index'/> is outside the valid range of indexes for the collection.</exception>
public ZipEntry this[int index]
{
get
{
return ((ZipEntry)(List[index]));
}
set
{
List[index] = value;
}
}
/// <summary>Adds a <see cref='OrganicBit.Zip.ZipEntry'/> with the specified value to the <see cref='OrganicBit.Zip.ZipEntryCollection'/>.</summary>
/// <param name='value'>The <see cref='OrganicBit.Zip.ZipEntry'/> to add.</param>
/// <returns>The index at which the new element was inserted.</returns>
/// <seealso cref='OrganicBit.Zip.ZipEntryCollection.AddRange'/>
public int Add(ZipEntry value)
{
return List.Add(value);
}
/// <summary>Copies the elements of an array to the end of the <see cref='OrganicBit.Zip.ZipEntryCollection'/>.</summary>
/// <param name='value'>An array of type <see cref='OrganicBit.Zip.ZipEntry'/> containing the objects to add to the collection.</param>
/// <returns>None.</returns>
/// <seealso cref='OrganicBit.Zip.ZipEntryCollection.Add'/>
public void AddRange(ZipEntry[] value)
{
for (int i = 0; (i < value.Length); i = (i + 1))
{
this.Add(value[i]);
}
}
/// <summary>Adds the contents of another <see cref='OrganicBit.Zip.ZipEntryCollection'/> to the end of the collection.</summary>
/// <param name='value'>A <see cref='OrganicBit.Zip.ZipEntryCollection'/> containing the objects to add to the collection.</param>
/// <returns>None.</returns>
/// <seealso cref='OrganicBit.Zip.ZipEntryCollection.Add'/>
public void AddRange(ZipEntryCollection value)
{
for (int i = 0; (i < value.Count); i = (i + 1))
{
this.Add(value[i]);
}
}
/// <summary>Gets a value indicating whether the <see cref='OrganicBit.Zip.ZipEntryCollection'/> contains the specified <see cref='OrganicBit.Zip.ZipEntry'/>.</summary>
/// <param name='value'>The <see cref='OrganicBit.Zip.ZipEntry'/> to locate.</param>
/// <returns>
/// <para><see langword='true'/> if the <see cref='OrganicBit.Zip.ZipEntry'/> is contained in the collection;
/// otherwise, <see langword='false'/>.</para>
/// </returns>
/// <seealso cref='OrganicBit.Zip.ZipEntryCollection.IndexOf'/>
public bool Contains(ZipEntry value)
{
return List.Contains(value);
}
/// <summary>Copies the <see cref='OrganicBit.Zip.ZipEntryCollection'/> values to a one-dimensional <see cref='System.Array'/> instance at the specified index.</summary>
/// <param name='array'><para>The one-dimensional <see cref='System.Array'/> that is the destination of the values copied from <see cref='OrganicBit.Zip.ZipEntryCollection'/> .</para></param>
/// <param name='index'>The index in <paramref name='array'/> where copying begins.</param>
/// <returns>None.</returns>
/// <exception cref='System.ArgumentException'><para><paramref name='array'/> is multidimensional.</para> <para>-or-</para> <para>The number of elements in the <see cref='OrganicBit.Zip.ZipEntryCollection'/> is greater than the available space between <paramref name='arrayIndex'/> and the end of <paramref name='array'/>.</para></exception>
/// <exception cref='System.ArgumentNullException'><paramref name='array'/> is <see langword='null'/>. </exception>
/// <exception cref='System.ArgumentOutOfRangeException'><paramref name='arrayIndex'/> is less than <paramref name='array'/>'s lowbound. </exception>
/// <seealso cref='System.Array'/>
public void CopyTo(ZipEntry[] array, int index)
{
List.CopyTo(array, index);
}
/// <summary>Returns the index of a <see cref='OrganicBit.Zip.ZipEntry'/> in the <see cref='OrganicBit.Zip.ZipEntryCollection'/>.</summary>
/// <param name='value'>The <see cref='OrganicBit.Zip.ZipEntry'/> to locate.</param>
/// <returns>
/// <para>The index of the <see cref='OrganicBit.Zip.ZipEntry'/> of <paramref name='value'/> in the
/// <see cref='OrganicBit.Zip.ZipEntryCollection'/>, if found; otherwise, -1.</para>
/// </returns>
/// <seealso cref='OrganicBit.Zip.ZipEntryCollection.Contains'/>
public int IndexOf(ZipEntry value)
{
return List.IndexOf(value);
}
/// <summary>Inserts a <see cref='OrganicBit.Zip.ZipEntry'/> into the <see cref='OrganicBit.Zip.ZipEntryCollection'/> at the specified index.</summary>
/// <param name='index'>The zero-based index where <paramref name='value'/> should be inserted.</param>
/// <param name=' value'>The <see cref='OrganicBit.Zip.ZipEntry'/> to insert.</param>
/// <returns><para>None.</para></returns>
/// <seealso cref='OrganicBit.Zip.ZipEntryCollection.Add'/>
public void Insert(int index, ZipEntry value)
{
List.Insert(index, value);
}
/// <summary>Returns an enumerator that can iterate through the <see cref='OrganicBit.Zip.ZipEntryCollection'/>.</summary>
/// <returns><para>None.</para></returns>
/// <seealso cref='System.Collections.IEnumerator'/>
public new ZipEntryEnumerator GetEnumerator()
{
return new ZipEntryEnumerator(this);
}
/// <summary>Removes a specific <see cref='OrganicBit.Zip.ZipEntry'/> from the <see cref='OrganicBit.Zip.ZipEntryCollection'/>.</summary>
/// <param name='value'>The <see cref='OrganicBit.Zip.ZipEntry'/> to remove from the <see cref='OrganicBit.Zip.ZipEntryCollection'/> .</param>
/// <returns><para>None.</para></returns>
/// <exception cref='System.ArgumentException'><paramref name='value'/> is not found in the Collection. </exception>
public void Remove(ZipEntry value)
{
List.Remove(value);
}
/// <summary>Enumerator for <see cref="ZipEntryCollection"/>.</summary>
public class ZipEntryEnumerator : object, IEnumerator
{
private IEnumerator baseEnumerator;
private IEnumerable temp;
/// <summary>Initializes a new instance of the <see cref="ZipEntryEnumerator"/> class.</summary>
public ZipEntryEnumerator(ZipEntryCollection mappings)
{
this.temp = ((IEnumerable)(mappings));
this.baseEnumerator = temp.GetEnumerator();
}
/// <summary>Gets the current entry.</summary>
public ZipEntry Current
{
get
{
return ((ZipEntry)(baseEnumerator.Current));
}
}
object IEnumerator.Current
{
get
{
return baseEnumerator.Current;
}
}
/// <summary>Advance the enumerator to the next entry in the collection.</summary>
/// <returns><c>true</c> if there are more entries; <c>false</c> if there are no more entires in the collection.</returns>
public bool MoveNext()
{
return baseEnumerator.MoveNext();
}
bool IEnumerator.MoveNext()
{
return baseEnumerator.MoveNext();
}
/// <summary>Set the enumerator to just before the start of the collection. Call <see cref="MoveNext"/> to advance to the first entry in the collection.</summary>
public void Reset()
{
baseEnumerator.Reset();
}
void IEnumerator.Reset()
{
baseEnumerator.Reset();
}
}
}
}
======================================================================
//ZipException.cs
using System;
using System.Runtime.Serialization;
namespace OrganicBit.Zip
{
/// <summary>Thrown whenever an error occurs during the build.</summary>
[Serializable]
public class ZipException : ApplicationException
{
/// <summary>Constructs an exception with no descriptive information.</summary>
public ZipException() : base()
{
}
/// <summary>Constructs an exception with a descriptive message.</summary>
/// <param name="message">The error message that explains the reason for the exception.</param>
public ZipException(String message) : base(message)
{
}
/// <summary>Constructs an exception with a descriptive message and a reference to the instance of the <c>Exception</c> that is the root cause of the this exception.</summary>
/// <param name="message">The error message that explains the reason for the exception.</param>
/// <param name="innerException">An instance of <c>Exception</c> that is the cause of the current Exception. If <paramref name="innerException"/> is non-null, then the current Exception is raised in a catch block handling <paramref>innerException</paramref>.</param>
public ZipException(String message, Exception innerException) : base(message, innerException)
{
}
/// <summary>Initializes a new instance of the BuildException class with serialized data.</summary>
/// <param name="info">The object that holds the serialized object data.</param>
/// <param name="context">The contextual information about the source or destination.</param>
public ZipException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
}
}
======================================================================
//ZipLib.cs
using System;
using System.IO;
using System.Text;
using System.Runtime.InteropServices;
namespace OrganicBit.Zip
{
/// <summary>Support methods for uncompressing zip files.</summary>
/// <remarks>
/// <para>This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g WinZip, InfoZip tools and compatible.</para>
/// <para>Encryption and multi volume ZipFile (span) are not supported. Old compressions used by old PKZip 1.x are not supported.</para>
/// <para>Copyright (C) 1998 Gilles Vollant. http://www.winimage.com/zLibDll/unzip.htm</para>
/// <para>C# wrapper by Gerry Shaw (gerry_shaw@yahoo.com). http://www.organicbit.com/zip/</para>
/// </remarks>
internal sealed class ZipLib
{
// prevent instances of this class from being constructed
private ZipLib() { }
/*
Create a zipfile.
pathname contain on Windows NT a filename like "c:\\zlib\\zlib111.zip" or on an Unix computer "zlib/zlib111.zip".
if the file pathname exist and append=1, the zip will be created at the end of the file. (useful if the file contain a self extractor code)
If the zipfile cannot be opened, the return value is NULL.
Else, the return value is a zipFile Handle, usable with other function of this zip package.
*/
/// <summary>Create a zip file.</summary>
[DllImport("zlib.dll", ExactSpelling = true, CharSet = CharSet.Ansi)]
public static extern IntPtr zipOpen(string fileName, int append);
/*
Open a file in the ZIP for writing.
filename : the filename in zip (if NULL, '-' without quote will be used
*zipfi contain supplemental information
if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local contains the extrafield data the the local header
if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global contains the extrafield data the the local header
if comment != NULL, comment contain the comment string
method contain the compression method (0 for store, Z_DEFLATED for deflate)
level contain the level of compression (can be Z_DEFAULT_COMPRESSION)
*/
/// <summary>Open a new zip entry for writing.</summary>
[DllImport("zlib.dll", ExactSpelling = true, CharSet = CharSet.Ansi)]
unsafe public static extern int zipOpenNewFileInZip(IntPtr handle,
string entryName,
ZipFileEntryInfo* entryInfoPtr,
byte[] extraField,
uint extraFieldLength,
byte[] extraFieldGlobal,
uint extraFieldGlobalLength,
string comment,
int method,
int level);
/// <summary>Write data to the zip file.</summary>
[DllImport("zlib.dll")]
public static extern int zipWriteInFileInZip(IntPtr handle, byte[] buffer, uint count);
/// <summary>Close the current entry in the zip file.</summary>
[DllImport("zlib.dll")]
public static extern int zipCloseFileInZip(IntPtr handle);
/// <summary>Close the zip file.</summary>
[DllImport("zlib.dll", ExactSpelling = true, CharSet = CharSet.Ansi)]
public static extern int zipClose(IntPtr handle, string comment);
/// <summary>Opens a zip file for reading.</summary>
/// <param name="fileName">The name of the zip to open. At this time only file names with ANSI (8 bit) characters are supported.</param>
/// <returns>
/// <para>A handle usable with other functions of the ZipLib class.</para>
/// <para>Otherwise IntPtr.Zero if the zip file could not e opened (file doen not exist or is not valid).</para>
/// </returns>
[DllImport("zlib.dll", ExactSpelling = true, CharSet = CharSet.Ansi)]
public static extern IntPtr unzOpen(string fileName);
/// <summary>Closes a zip file opened with unzipOpen.</summary>
/// <param name="handle">The zip file handle opened by <see cref="unzOpenCurrentFile"/>.</param>
/// <remarks>If there are files inside the zip file opened with <see cref="unzOpenCurrentFile"/> these files must be closed with <see cref="unzCloseCurrentFile"/> before call <c>unzClose</c>.</remarks>
/// <returns>
/// <para>Zero if there was no error.</para>
/// <para>Otherwise a value less than zero. See <see cref="ErrorCode"/> for the specific reason.</para>
/// </returns>
[DllImport("zlib.dll")]
public static extern int unzClose(IntPtr handle);
/// <summary>Get global information about the zip file.</summary>
/// <param name="handle">The zip file handle opened by <see cref="unzOpenCurrentFile"/>.</param>
/// <param name="globalInfoPtr">An address of a <see cref="ZipFileInfo"/> struct to hold the information. No preparation of the structure is needed.</param>
/// <returns>
/// <para>Zero if there was no error.</para>
/// <para>Otherwise a value less than zero. See <see cref="ErrorCode"/> for the specific reason.</para>
/// </returns>
[DllImport("zlib.dll")]
public unsafe static extern int unzGetGlobalInfo(IntPtr handle, ZipFileInfo* globalInfoPtr);
/// <summary>Get the comment associated with the entire zip file.</summary>
/// <param name="handle">The zip file handle opened by <see cref="unzOpenCurrentFile"/></param>
/// <param name="commentBuffer">The buffer to hold the comment.</param>
/// <param name="commentBufferLength">The length of the buffer in bytes (8 bit characters).</param>
/// <returns>
/// <para>The number of characters in the comment if there was no error.</para>
/// <para>Otherwise a value less than zero. See <see cref="ErrorCode"/> for the specific reason.</para>
/// </returns>
[DllImport("zlib.dll")]
public static extern int unzGetGlobalComment(IntPtr handle, sbyte[] commentBuffer, uint commentBufferLength);
/// <summary>Set the current file of the zip file to the first file.</summary>
/// <param name="handle">The zip file handle opened by <see cref="unzOpenCurrentFile"/>.</param>
/// <returns>
/// <para>Zero if there was no error.</para>
/// <para>Otherwise a value less than zero. See <see cref="ErrorCode"/> for the specific reason.</para>
/// </returns>
[DllImport("zlib.dll")]
public static extern int unzGoToFirstFile(IntPtr handle);
/// <summary>Set the current file of the zip file to the next file.</summary>
/// <param name="handle">The zip file handle opened by <see cref="unzOpenCurrentFile"/>.</param>
/// <returns>
/// <para>Zero if there was no error.</para>
/// <para>Otherwise <see cref="ErrorCode.EndOfListOfFile"/> if there are no more entries.</para>
/// </returns>
[DllImport("zlib.dll")]
public static extern int unzGoToNextFile(IntPtr handle);
/// <summary>Try locate the entry in the zip file.</summary>
/// <param name="handle">The zip file handle opened by <see cref="unzOpenCurrentFile"/>.</param>
/// <param name="entryName">The name of the entry to look for.</param>
/// <param name="caseSensitivity">If 0 use the OS default. If 1 use case sensitivity like strcmp, Unix style. If 2 do not use case sensitivity like strcmpi, Windows style.</param>
/// <returns>
/// <para>Zero if there was no error.</para>
/// <para>Otherwise <see cref="ErrorCode.EndOfListOfFile"/> if there are no more entries.</para>
/// </returns>
[DllImport("zlib.dll", ExactSpelling = true, CharSet = CharSet.Ansi)]
public static extern int unzLocateFile(IntPtr handle, string entryName, int caseSensitivity);
/// <summary>Get information about the current entry in the zip file.</summary>
/// <param name="handle">The zip file handle opened by <see cref="unzOpenCurrentFile"/>.</param>
/// <param name="entryInfoPtr">A ZipEntryInfo struct to hold information about the entry or null.</param>
/// <param name="entryNameBuffer">An array of sbyte characters to hold the entry name or null.</param>
/// <param name="entryNameBufferLength">The length of the entryNameBuffer in bytes.</param>
/// <param name="extraField">An array to hold the extra field data for the entry or null.</param>
/// <param name="extraFieldLength">The length of the extraField array in bytes.</param>
/// <param name="commentBuffer">An array of sbyte characters to hold the entry name or null.</param>
/// <param name="commentBufferLength">The length of theh commentBuffer in bytes.</param>
/// <remarks>
/// <para>If entryInfoPtr is not null the structure will contain information about the current file.</para>
/// <para>If entryNameBuffer is not null the name of the entry will be copied into it.</para>
/// <para>If extraField is not null the extra field data of the entry will be copied into it.</para>
/// <para>If commentBuffer is not null the comment of the entry will be copied into it.</para>
/// </remarks>
/// <returns>
/// <para>Zero if there was no error.</para>
/// <para>Otherwise a value less than zero. See <see cref="ErrorCode"/> for the specific reason.</para>
/// </returns>
[DllImport("zlib.dll", ExactSpelling = true, CharSet = CharSet.Ansi)]
public unsafe static extern int unzGetCurrentFileInfo(IntPtr handle, ZipEntryInfo* entryInfoPtr,
sbyte[] entryNameBuffer, uint entryNameBufferLength,
byte[] extraField, uint extraFieldLength,
sbyte[] commentBuffer, uint commentBufferLength);
/// <summary>Open the zip file entry for reading.</summary>
/// <param name="handle">The zip file handle opened by <see cref="unzOpenCurrentFile"/>.</param>
/// <returns>
/// <para>Zero if there was no error.</para>
/// <para>Otherwise a value from <see cref="ErrorCode"/>.</para>
/// </returns>
[DllImport("zlib.dll")]
public static extern int unzOpenCurrentFile(IntPtr handle);
/// <summary>Close the file entry opened by <see cref="unzOpenCurrentFile"/>.</summary>
/// <param name="handle">The zip file handle opened by <see cref="unzOpenCurrentFile"/>.</param>
/// <returns>
/// <para>Zero if there was no error.</para>
/// <para>CrcError if the file was read but the Crc does not match.</para>
/// <para>Otherwise a value from <see cref="ErrorCode"/>.</para>
/// </returns>
[DllImport("zlib.dll")]
public static extern int unzCloseCurrentFile(IntPtr handle);
/// <summary>Read bytes from the current zip file entry.</summary>
/// <param name="handle">The zip file handle opened by <see cref="unzOpenCurrentFile"/>.</param>
/// <param name="buffer">Buffer to store the uncompressed data into.</param>
/// <param name="count">Number of bytes to write from <paramref name="buffer"/>.</param>
/// <returns>
/// <para>The number of byte copied if somes bytes are copied.</para>
/// <para>Zero if the end of file was reached.</para>
/// <para>Less than zero with error code if there is an error. See <see cref="ErrorCode"/> for a list of possible error codes.</para>
/// </returns>
[DllImport("zlib.dll")]
public static extern int unzReadCurrentFile(IntPtr handle, byte[] buffer, uint count);
/// <summary>Give the current position in uncompressed data of the zip file entry currently opened.</summary>
/// <param name="handle">The zip file handle opened by <see cref="unzOpenCurrentFile"/>.</param>
/// <returns>The number of bytes into the uncompressed data read so far.</returns>
[DllImport("zlib.dll")]
public static extern long unztell(IntPtr handle);
/// <summary>Determine if the end of the zip file entry has been reached.</summary>
/// <param name="handle">The zip file handle opened by <see cref="unzOpenCurrentFile"/>.</param>
/// <returns>
/// <para>One if the end of file was reached.</para>
/// <para>Zero if elsewhere.</para>
/// </returns>
[DllImport("zlib.dll")]
public static extern int unzeof(IntPtr handle);
/// <summary>Converts a CLR string to a 8 bit ANSI array of characters.</summary>
/// <param name="str">The string to convert.</param>
/// <returns>A 8 bit ANSI array of characters.</returns>
public static sbyte[] StringToAnsi(string str)
{
int length = str.Length;
sbyte[] chars = new sbyte[length + 1];
for (int i = 0; i < length; i++)
{
chars[i] = (sbyte)str[i];
}
return chars;
}
/// <summary>Converst an 8 bit ANSI C style string to a CLR string.</summary>
/// <param name="chars">The array of a characters that holds the string.</param>
/// <returns>The CLR string representing the characters passed in.</returns>
public static string AnsiToString(sbyte[] chars)
{
int length = chars.Length;
StringBuilder builder = new StringBuilder();
for (int i = 0; i < length; i++)
{
builder.Append((char)chars[i]);
}
return builder.ToString();
}
}
/// <summary>List of possible error codes.</summary>
internal enum ErrorCode : int
{
/// <summary>No error.</summary>
Ok = 0,
/// <summary>Unknown error.</summary>
Error = -1,
/// <summary>Last entry in directory reached.</summary>
EndOfListOfFile = -100,
/// <summary>Parameter error.</summary>
ParameterError = -102,
/// <summary>Zip file is invalid.</summary>
BadZipFile = -103,
/// <summary>Internal program error.</summary>
InternalError = -104,
/// <summary>Crc values do not match.</summary>
CrcError = -105
}
/// <summary>Global information about the zip file.</summary>
[StructLayout(LayoutKind.Sequential)]
internal struct ZipFileInfo
{
/// <summary>The number of entries in the directory.</summary>
public UInt32 EntryCount;
/// <summary>Length of zip file comment in bytes (8 bit characters).</summary>
public UInt32 CommentLength;
}
[StructLayout(LayoutKind.Sequential)]
internal struct ZipFileEntryInfo
{
public ZipDateTimeInfo DateTime;
public UInt32 DosDate;
public UInt32 InternalFileAttributes; // 2 bytes
public UInt32 ExternalFileAttributes; // 4 bytes
}
/// <summary>Custom ZipLib date time structure.</summary>
[StructLayout(LayoutKind.Sequential)]
internal struct ZipDateTimeInfo
{
/// <summary>Seconds after the minute - [0,59]</summary>
public UInt32 Seconds;
/// <summary>Minutes after the hour - [0,59]</summary>
public UInt32 Minutes;
/// <summary>Hours since midnight - [0,23]</summary>
public UInt32 Hours;
/// <summary>Day of the month - [1,31]</summary>
public UInt32 Day;
/// <summary>Months since January - [0,11]</summary>
public UInt32 Month;
/// <summary>Years - [1980..2044]</summary>
public UInt32 Year;
// implicit conversion from DateTime to ZipDateTimeInfo
public static implicit operator ZipDateTimeInfo(DateTime date)
{
ZipDateTimeInfo d;
d.Seconds = (uint)date.Second;
d.Minutes = (uint)date.Minute;
d.Hours = (uint)date.Hour;
d.Day = (uint)date.Day;
d.Month = (uint)date.Month - 1;
d.Year = (uint)date.Year;
return d;
}
}
/// <summary>Information stored in zip file directory about an entry.</summary>
[StructLayout(LayoutKind.Sequential)]
internal struct ZipEntryInfo
{
// <summary>Version made by (2 bytes).</summary>
public UInt32 Version;
/// <summary>Version needed to extract (2 bytes).</summary>
public UInt32 VersionNeeded;
/// <summary>General purpose bit flag (2 bytes).</summary>
public UInt32 Flag;
/// <summary>Compression method (2 bytes).</summary>
public UInt32 CompressionMethod;
/// <summary>Last mod file date in Dos fmt (4 bytes).</summary>
public UInt32 DosDate;
/// <summary>Crc-32 (4 bytes).</summary>
public UInt32 Crc;
/// <summary>Compressed size (4 bytes).</summary>
public UInt32 CompressedSize;
/// <summary>Uncompressed size (4 bytes).</summary>
public UInt32 UncompressedSize;
/// <summary>Filename length (2 bytes).</summary>
public UInt32 FileNameLength;
/// <summary>Extra field length (2 bytes).</summary>
public UInt32 ExtraFieldLength;
/// <summary>File comment length (2 bytes).</summary>
public UInt32 CommentLength;
/// <summary>Disk number start (2 bytes).</summary>
public UInt32 DiskStartNumber;
/// <summary>Internal file attributes (2 bytes).</summary>
public UInt32 InternalFileAttributes;
/// <summary>External file attributes (4 bytes).</summary>
public UInt32 ExternalFileAttributes;
/// <summary>File modification date of entry.</summary>
public ZipDateTimeInfo DateTime;
}
}
======================================================================
//ZipReader.cs
using System;
using System.Collections;
using System.IO;
using System.Runtime.Serialization;
namespace OrganicBit.Zip
{
/// <summary>Provides support for reading files in the ZIP file format. Includes support for both compressed and uncompressed entries.</summary>
/// <example>This example shows how to view the entries in a ZIP file.
/// <code>
/// public static void View(string zipFileName) {
/// ZipReader reader = new ZipReader(zipFileName);
///
/// Console.WriteLine("Archive: {0} ({1} files)", zipFileName, reader.Entries.Count);
/// Console.WriteLine(reader.Comment);
///
/// string format = "{0,8} {1,8} {2,5} {3,10} {4,5} {5}";
/// Console.WriteLine(format, " Length ", " Size ", "Ratio", " Date ", "Time ", "Name");
/// Console.WriteLine(format, "--------", "--------", "-----", "----------", "-----", "----");
///
/// foreach (ZipEntry entry in reader.Entries) {
/// if (!entry.IsDirectory) {
/// Console.WriteLine(format,
/// entry.Length,
/// entry.CompressedLength,
/// entry.Ratio.ToString("P0"),
/// entry.ModifiedTime.ToString("yyyy-MM-dd"),
/// entry.ModifiedTime.ToString("hh:mm"),
/// entry.Name);
/// }
/// }
/// reader.Close();
/// }
/// </code>
/// </example>
/// <example>This example shows how to extract files from a ZIP file.
/// <code>
/// public static void Extract(string zipFileName) {
/// ZipReader reader = new ZipReader(zipFileName);
/// Console.WriteLine("Archive: {0}", zipFileName);
/// Console.WriteLine(reader.Comment);
///
/// // buffer to hold temp bytes
/// byte[] buffer = new byte[4096];
/// int byteCount;
///
/// // Get the zipped entries
/// while (reader.MoveNext()) {
/// ZipEntry entry = reader.Current;
///
/// if (entry.IsDirectory) {
/// Directory.CreateDirectory(entry.Name);
/// } else {
/// Console.Write(" {0}", entry.Name);
///
/// // create output stream
/// FileStream writer = File.Open(entry.Name, FileMode.Create);
///
/// // write uncompressed data
/// while ((byteCount = reader.Read(buffer, 0, buffer.Length)) > 0) {
/// Console.Write(".");
/// writer.Write(buffer, 0, byteCount);
/// }
/// writer.Close();
/// Console.WriteLine();
/// }
/// }
/// reader.Close();
/// }
/// </code>
/// </example>
public class ZipReader : IEnumerator, IDisposable
{
/// <summary>ZipFile handle to read data from.</summary>
IntPtr _handle = IntPtr.Zero;
/// <summary>Name of zip file.</summary>
string _fileName = null;
/// <summary>Contents of zip file directory.</summary>
ZipEntryCollection _entries = null;
/// <summary>Global zip file comment.</summary>
string _comment = null;
/// <summary>True if an entry is open for reading.</summary>
bool _entryOpen = false;
/// <summary>Current zip entry open for reading.</summary>
ZipEntry _current = null;
/// <summary>Initializes a instance of the <see cref="ZipReader"/> class for reading the zip file with the given name.</summary>
/// <param name="fileName">The name of zip file that will be read.</param>
public ZipReader(string fileName)
{
_fileName = fileName;
_handle = ZipLib.unzOpen(fileName);
if (_handle == IntPtr.Zero)
{
string msg = String.Format("Could not open zip file '{0}'.", fileName);
throw new ZipException(msg);
}
}
/// <summary>Cleans up the resources used by this zip file.</summary>
~ZipReader()
{
CloseFile();
}
/// <remarks>Dispose is synonym for Close.</remarks>
void IDisposable.Dispose()
{
Close();
}
/// <summary>Closes the zip file and releases any resources.</summary>
public void Close()
{
// Free unmanaged resources.
CloseFile();
// If base type implements IDisposable we would call it here.
// Request the system not call the finalizer method for this object.
GC.SuppressFinalize(this);
}
/// <summary>Gets the name of the zip file that was passed to the constructor.</summary>
public string Name
{
get { return _fileName; }
}
/// <summary>Gets the global comment for the zip file.</summary>
public string Comment
{
get
{
if (_comment == null)
{
ZipFileInfo info;
int result = 0;
unsafe
{
result = ZipLib.unzGetGlobalInfo(_handle, &info);
}
if (result < 0)
{
string msg = String.Format("Could not read comment from zip file '{0}'.", Name);
throw new ZipException(msg);
}
sbyte[] buffer = new sbyte[info.CommentLength];
result = ZipLib.unzGetGlobalComment(_handle, buffer, (uint)buffer.Length);
if (result < 0)
{
string msg = String.Format("Could not read comment from zip file '{0}'.", Name);
throw new ZipException(msg);
}
_comment = ZipLib.AnsiToString(buffer);
}
return _comment;
}
}
/// <summary>Gets a <see cref="ZipEntryCollection"/> object that contains all the entries in the zip file directory.</summary>
public ZipEntryCollection Entries
{
get
{
if (_entries == null)
{
_entries = new ZipEntryCollection();
int result = ZipLib.unzGoToFirstFile(_handle);
while (result == 0)
{
ZipEntry entry = new ZipEntry(_handle);
_entries.Add(entry);
result = ZipLib.unzGoToNextFile(_handle);
}
}
return _entries;
}
}
object IEnumerator.Current
{
get
{
return _current;
}
}
/// <summary>Gets the current entry in the zip file..</summary>
public ZipEntry Current
{
get
{
return _current;
}
}
/// <summary>Advances the enumerator to the next element of the collection.</summary>
/// <summary>Sets <see cref="Current"/> to the next zip entry.</summary>
/// <returns><c>true</c> if the next entry is not <c>null</c>; otherwise <c>false</c>.</returns>
public bool MoveNext()
{
// close any open entry
CloseEntry();
int result;
if (_current == null)
{
result = ZipLib.unzGoToFirstFile(_handle);
}
else
{
result = ZipLib.unzGoToNextFile(_handle);
}
if (result < 0)
{
// last entry found - not an exceptional case
_current = null;
}
else
{
// entry found
OpenEntry();
}
return (_current != null);
}
/// <summary>Move to just before the first entry in the zip directory.</summary>
public void Reset()
{
CloseEntry();
_current = null;
}
/// <summary>Seek to the specified entry.</summary>
/// <param name="entryName">The name of the entry to seek to.</param>
public void Seek(string entryName)
{
CloseEntry();
int result = ZipLib.unzLocateFile(_handle, entryName, 0);
if (result < 0)
{
string msg = String.Format("Could not locate entry named '{0}'.", entryName);
throw new ZipException(msg);
}
OpenEntry();
}
private void OpenEntry()
{
_current = new ZipEntry(_handle);
int result = ZipLib.unzOpenCurrentFile(_handle);
if (result < 0)
{
_current = null;
throw new ZipException("Could not open entry for reading.");
}
_entryOpen = true;
}
/// <summary>Uncompress a block of bytes from the current zip entry and writes the data in a given buffer.</summary>
/// <param name="buffer">The array to write data into.</param>
/// <param name="index">The byte offset in <paramref name="buffer"/> at which to begin writing.</param>
/// <param name="count">The maximum number of bytes to read.</param>
public int Read(byte[] buffer, int index, int count)
{
if (index != 0)
{
throw new ArgumentException("index", "Only index values of zero currently supported.");
}
int bytesRead = ZipLib.unzReadCurrentFile(_handle, buffer, (uint)count);
if (bytesRead < 0)
{
throw new ZipException("Error reading zip entry.");
}
return bytesRead;
}
private void CloseEntry()
{
if (_entryOpen)
{
int result = ZipLib.unzCloseCurrentFile(_handle);
if (result < 0)
{
switch ((ErrorCode)result)
{
case ErrorCode.CrcError:
throw new ZipException("All the file was read but the CRC did not match.");
default:
throw new ZipException("Could not close zip entry.");
}
}
_entryOpen = false;
}
}
private void CloseFile()
{
if (_handle != IntPtr.Zero)
{
CloseEntry();
int result = ZipLib.unzClose(_handle);
if (result < 0)
{
throw new ZipException("Could not close zip file.");
}
_handle = IntPtr.Zero;
}
}
}
}
======================================================================
//ZipWriter.cs
using System;
using System.IO;
using System.Runtime.Serialization;
namespace OrganicBit.Zip
{
/// <summary>Provides support for writing files in the ZIP file format. Includes support for both compressed and uncompressed entries.</summary>
/// <example>This example shows how to create a ZIP file.
/// <code>
/// public static void Add(string zipFileName, string[] entryPatterns) {
/// string currentDirectory = Directory.GetCurrentDirectory();
/// Console.WriteLine("Creating {0}", zipFileName);
///
/// ZipWriter writer = new ZipWriter(zipFileName);
///
/// // buffer to hold temp bytes
/// byte[] buffer = new byte[4096];
/// int byteCount;
///
/// // add files to archive
/// foreach (string pattern in entryPatterns) {
/// foreach (string path in Directory.GetFiles(currentDirectory, pattern)) {
/// string fileName = Path.GetFileName(path);
/// Console.Write("Adding {0}", fileName);
///
/// ZipEntry entry = new ZipEntry(fileName);
/// entry.ModifiedTime = File.GetLastWriteTime(fileName);
/// entry.Comment = "local file comment";
///
/// writer.AddEntry(entry);
///
/// FileStream reader = File.OpenRead(entry.Name);
/// while ((byteCount = reader.Read(buffer, 0, buffer.Length)) > 0) {
/// Console.Write(".");
/// writer.Write(buffer, 0, byteCount);
/// }
/// reader.Close();
/// Console.WriteLine();
/// }
/// }
///
/// writer.Close();
/// }
/// </code>
/// </example>
public class ZipWriter : IDisposable
{
/// <summary>Name of the zip file.</summary>
string _fileName;
/// <summary>Zip file global comment.</summary>
string _comment = "";
/// <summary>True if currently writing a new zip file entry.</summary>
bool _entryOpen = false;
/// <summary>Zip file handle.</summary>
IntPtr _handle = IntPtr.Zero;
/// <summary>Initializes a new instance fo the <see cref="ZipWriter"/> class with a specified file name. Any Existing file will be overwritten.</summary>
/// <param name="fileName">The name of the zip file to create.</param>
public ZipWriter(string fileName)
{
_fileName = fileName;
_handle = ZipLib.zipOpen(fileName, 0);
if (_handle == IntPtr.Zero)
{
string msg = String.Format("Could not open zip file '{0}' for writing.", fileName);
throw new ZipException(msg);
}
}
/// <summary>Cleans up the resources used by this zip file.</summary>
~ZipWriter()
{
CloseFile();
}
/// <remarks>Dispose is synonym for Close.</remarks>
void IDisposable.Dispose()
{
Close();
}
/// <summary>Closes the zip file and releases any resources.</summary>
public void Close()
{
// Free unmanaged resources.
CloseFile();
// If base type implements IDisposable we would call it here.
// Request the system not call the finalizer method for this object.
GC.SuppressFinalize(this);
}
/// <summary>Gets the name of the zip file.</summary>
public string Name
{
get
{
return _fileName;
}
}
/// <summary>Gets and sets the zip file comment.</summary>
public string Comment
{
get { return _comment; }
set { _comment = value; }
}
/// <summary>Creates a new zip entry in the directory and positions the stream to the start of the entry data.</summary>
/// <param name="entry">The zip entry to be written.</param>
/// <remarks>Closes the current entry if still active.</remarks>
public void AddEntry(ZipEntry entry)
{
ZipFileEntryInfo info;
info.DateTime = entry.ModifiedTime;
int result;
unsafe
{
byte[] extra = null;
uint extraLength = 0;
if (entry.ExtraField != null)
{
extra = entry.ExtraField;
extraLength = (uint)entry.ExtraField.Length;
}
result = ZipLib.zipOpenNewFileInZip(
_handle,
entry.Name,
&info,
extra,
extraLength,
null, 0,
entry.Comment,
(int)entry.Method,
entry.Level);
}
_entryOpen = true;
}
/// <summary>Compress a block of bytes from the given buffer and writes them into the current zip entry.</summary>
/// <param name="buffer">The array to read data from.</param>
/// <param name="index">The byte offset in <paramref name="buffer"/> at which to begin reading.</param>
/// <param name="count">The maximum number of bytes to write.</param>
public void Write(byte[] buffer, int index, int count)
{
int result = ZipLib.zipWriteInFileInZip(_handle, buffer, (uint)count);
}
private void CloseEntry()
{
if (_entryOpen)
{
int result = ZipLib.zipCloseFileInZip(_handle);
_entryOpen = false;
}
}
void CloseFile()
{
if (_handle != IntPtr.Zero)
{
CloseEntry();
int result = ZipLib.zipClose(_handle, _comment);
if (result < 0)
{
throw new ZipException("Could not close zip file.");
}
_handle = IntPtr.Zero;
}
}
}
}
nightmoon
等级:青蜂侠
财产:10520
经验:8390
魅力:2037
注册:2002-8-24
登录:2003-4-21
文章:464
签定:辽宁省沈阳市
Re:用 .Net 实现 Zip
good
WS.NET
等级:侠圣
财产:11120
经验:82342
魅力:7480
注册:2002-9-13
登录:2003-4-23
文章:2468
签定:北京市联通
Re:用 .Net 实现 Zip
好文章!
以前见过VC++的,现在C#的也出来了,太棒啦!
这么长,得赶紧试试。。。