前面介绍了六种.NET组件,其中有一种组件是写文件的压缩和解压,现在介绍另一种文件的解压缩组件SharpZipLib。在这个组件介绍系列中,只为简单的介绍组件的背景和简单的应用,读者在阅读时可以结合官网的相关介绍和在本地实际操作。
相关的组件功能非常强大,在笔者的介绍中只是提及到简单的应用,需要了解更多的操作和特性,可以根据官网介绍,或者查看DLL文件的相关类和方法,以此来扩展相关的业务需要。
SharpZipLib是一个完全在C#中为.NET平台编写的Zip,GZip,Tar和BZip2库。
一.SharpZipLib组件概述:ziplib(SharpZipLib,以前的NZipLib)是一个完全在C#为.NET平台编写的Zip,GZip,Tar和BZip2库。它实现为一个程序集(可安装在GAC中),因此可以轻松地集成到其他项目(任何.NET语言)中。 #ziplib的创建者这样说:“我已经将zip库移植到C#,因为我需要gzip / zip压缩,我不想使用libzip.dll或类似的东西我想要的所有在纯C#“。
SharpZipLib官网提供的下载操作:.NET 1.1,.NET 2.0(3.5,4.0),.NET CF 1.0,.NET CF 2.0的装配:下载237 KB,源代码和示例下载708 KB;源代码和示例下载708 KB;帮助文件下载1208 KB;
SharpZipLib是在GPL下发布,遵守开源协议。
二.SharpZipLib核心类和方法介绍:以上简单的介绍了SharpZipLib组件的相关背景,现在具体看一下该组件的相关核心类和方法:

1.ZipOutputStream类PutNextEntry():public void PutNextEntry(ZipEntry entry){bool hasCrc;if (entry == null){throw new ArgumentNullException("entry");}if (this.entries == null){throw new InvalidOperationException("ZipOutputStream was finished");}if (this.curEntry != null){this.CloseEntry();}if (this.entries.Count == 0x7fffffff){throw new ZipException("Too many entries for Zip file");}CompressionMethod compressionMethod = entry.CompressionMethod;int defaultCompressionLevel = this.defaultCompressionLevel;entry.Flags &= 0x800;this.patchEntryHeader = false;if (entry.Size == 0L){entry.CompressedSize = entry.Size;entry.Crc = 0L;compressionMethod = CompressionMethod.Stored;hasCrc = true;}else{hasCrc = (entry.Size >= 0L) && entry.HasCrc;if (compressionMethod == CompressionMethod.Stored){if (!hasCrc){if (!base.CanPatchEntries){compressionMethod = CompressionMethod.Deflated;defaultCompressionLevel = 0;}}else{entry.CompressedSize = entry.Size;hasCrc = entry.HasCrc;}}}if (!hasCrc){if (!base.CanPatchEntries){entry.Flags |= 8;}else{this.patchEntryHeader = true;}}if (base.Password != null){entry.IsCrypted = true;if (entry.Crc < 0L){entry.Flags |= 8;}}entry.Offset = this.offset;entry.CompressionMethod = compressionMethod;this.curMethod = compressionMethod;this.sizePatchPos = -1L;if ((this.useZip64_ == UseZip64.On) || ((entry.Size < 0L) && (this.useZip64_ == UseZip64.Dynamic))){entry.ForceZip64();}this.WriteLeInt(0x4034b50);this.WriteLeShort(entry.Version);this.WriteLeShort(entry.Flags);this.WriteLeShort((byte) entry.CompressionMethodForHeader);this.WriteLeInt((int) entry.DosTime);if (hasCrc){this.WriteLeInt((int) entry.Crc);if (entry.LocalHeaderRequiresZip64){this.WriteLeInt(-1);this.WriteLeInt(-1);}else{this.WriteLeInt(entry.IsCrypted ? (((int) entry.CompressedSize) + 12) : ((int) entry.CompressedSize));this.WriteLeInt((int) entry.Size);}}else{if (this.patchEntryHeader){this.crcPatchPos = base.baseOutputStream_.Position;}this.WriteLeInt(0);if (this.patchEntryHeader){this.sizePatchPos = base.baseOutputStream_.Position;}if (entry.LocalHeaderRequiresZip64 || this.patchEntryHeader){this.WriteLeInt(-1);this.WriteLeInt(-1);}else{this.WriteLeInt(0);this.WriteLeInt(0);}}byte[] buffer = ZipConstants.ConvertToArray(entry.Flags, entry.Name);if (buffer.Length > 0xffff){throw new ZipException("Entry name too long.");}ZipExtraData extraData = new ZipExtraData(entry.ExtraData);if (entry.LocalHeaderRequiresZip64){extraData.StartNewEntry();if (hasCrc){extraData.AddLeLong(entry.Size);extraData.AddLeLong(entry.CompressedSize);}else{extraData.AddLeLong(-1L);extraData.AddLeLong(-1L);}extraData.AddNewEntry(1);if (!extraData.Find(1)){throw new ZipException("Internal error cant find extra data");}if (this.patchEntryHeader){this.sizePatchPos = extraData.CurrentReadIndex;}}else{extraData.Delete(1);}if (entry.AESKeySize > 0){AddExtraDataAES(entry, extraData);}byte[] entryData = extraData.GetEntryData();this.WriteLeShort(buffer.Length);this.WriteLeShort(entryData.Length);if (buffer.Length > 0){base.baseOutputStream_.Write(buffer, 0, buffer.Length);}if (entry.LocalHeaderRequiresZip64 && this.patchEntryHeader){this.sizePatchPos += base.baseOutputStream_.Position;}if (entryData.Length > 0){base.baseOutputStream_.Write(entryData, 0, entryData.Length);}this.offset += (30 + buffer.Length) + entryData.Length;if (entry.AESKeySize > 0){this.offset += entry.AESOverheadSize;}this.curEntry = entry;this.crc.Reset();if (compressionMethod == CompressionMethod.Deflated){base.deflater_.Reset();base.deflater_.SetLevel(defaultCompressionLevel);}this.size = 0L;if (entry.IsCrypted){if (entry.AESKeySize > 0){this.WriteAESHeader(entry);}else if (entry.Crc < 0L){this.WriteEncryptionHeader(entry.DosTime << 0x10);}else{this.WriteEncryptionHeader(entry.Crc);}}}
2.ZipOutputStream类Finish():public override void Finish(){if (this.entries != null){if (this.curEntry != null){this.CloseEntry();}long count = this.entries.Count;long sizeEntries = 0L;foreach (ZipEntry entry in this.entries){this.WriteLeInt(0x2014b50);this.WriteLeShort(0x33);this.WriteLeShort(entry.Version);this.WriteLeShort(entry.Flags);this.WriteLeShort((short) entry.CompressionMethodForHeader);this.WriteLeInt((int) entry.DosTime);this.WriteLeInt((int) entry.Crc);if (entry.IsZip64Forced() || (entry.CompressedSize >= 0xffffffffL)){this.WriteLeInt(-1);}else{this.WriteLeInt((int) entry.CompressedSize);}if (entry.IsZip64Forced() || (entry.Size >= 0xffffffffL)){this.WriteLeInt(-1);}else{this.WriteLeInt((int) entry.Size);}byte[] buffer = ZipConstants.ConvertToArray(entry.Flags, entry.Name);if (buffer.Length > 0xffff){throw new ZipException("Name too long.");}ZipExtraData extraData = new ZipExtraData(entry.ExtraData);if (entry.CentralHeaderRequiresZip64){extraData.StartNewEntry();if (entry.IsZip64Forced() || (entry.Size >= 0xffffffffL)){extraData.AddLeLong(entry.Size);}if (entry.IsZip64Forced() || (entry.CompressedSize >= 0xffffffffL)){extraData.AddLeLong(entry.CompressedSize);}if (entry.Offset >= 0xffffffffL){extraData.AddLeLong(entry.Offset);}extraData.AddNewEntry(1);}else{extraData.Delete(1);}if (entry.AESKeySize > 0){AddExtraDataAES(entry, extraData);}byte[] entryData = extraData.GetEntryData();byte[] buffer3 = (entry.Comment != null) ? ZipConstants.ConvertToArray(entry.Flags, entry.Comment) : new byte[0];if (buffer3.Length > 0xffff){throw new ZipException("Comment too long.");}this.WriteLeShort(buffer.Length);this.WriteLeShort(entryData.Length);this.WriteLeShort(buffer3.Length);this.WriteLeShort(0);this.WriteLeShort(0);if (entry.ExternalFileAttributes != -1){this.WriteLeInt(entry.ExternalFileAttributes);}else if (entry.IsDirectory){this.WriteLeInt(0x10);}else{this.WriteLeInt(0);}if (entry.Offset >= 0xffffffffL){this.WriteLeInt(-1);}else{this.WriteLeInt((int) entry.Offset);}if (buffer.Length > 0){base.baseOutputStream_.Write(buffer, 0, buffer.Length);}if (entryData.Length > 0){base.baseOutputStream_.Write(entryData, 0, entryData.Length);}if (buffer3.Length > 0){base.baseOutputStream_.Write(buffer3, 0, buffer3.Length);}sizeEntries += ((0x2e + buffer.Length) + entryData.Length) + buffer3.Length;}using (ZipHelperStream stream = new ZipHelperStream(base.baseOutputStream_)){stream.WriteEndOfCentralDirectory(count, sizeEntries, this.offset, this.zipComment);}this.entries = null;}}
3.ZipEntry类Clone():public object Clone(){ZipEntry entry = (ZipEntry) base.MemberwiseClone();if (this.extra != null){entry.extra = new byte[this.extra.Length];Array.Copy(this.extra, 0, entry.extra, 0, this.extra.Length);}return entry;}
4.ZipOutputStream类Write():public override void Write(byte[] buffer, int offset, int count){if (this.curEntry == null){throw new InvalidOperationException("No open entry.");}if (buffer == null){throw new ArgumentNullException("buffer");}if (offset < 0){throw new ArgumentOutOfRangeException("offset", "Cannot be negative");}if (count < 0){throw new ArgumentOutOfRangeException("count", "Cannot be negative");}if ((buffer.Length - offset) < count){throw new ArgumentException("Invalid offset/count combination");}this.crc.Update(buffer, offset, count);this.size += count;switch (this.curMethod){case CompressionMethod.Stored:if (base.Password != null){this.CopyAndEncrypt(buffer, offset, count);}else{base.baseOutputStream_.Write(buffer, offset, count);}break;case CompressionMethod.Deflated:base.Write(buffer, offset, count);break;}}
三.SharpZipLib实例: 1.压缩单个文件:
/// <summary>/// 压缩单个文件/// </summary>/// <param name="fileToZip">要压缩的文件</param>/// <param name="zipedFile">压缩后的文件</param>/// <param name="compressionLevel">压缩等级</param>/// <param name="blockSize">每次写入大小</param>public static void ZipFile(string fileToZip, string zipedFile, int compressionLevel, int blockSize){if (string.IsNullOrEmpty(fileToZip)){throw new ArgumentNullException(fileToZip);}if (string.IsNullOrEmpty(zipedFile)){throw new ArgumentNullException(zipedFile);}if (!File.Exists(fileToZip)){throw new FileNotFoundException("指定要压缩的文件: " + fileToZip + " 不存在!");}try{using (var zipFile = File.Create(zipedFile)){using (var zipStream = new ZipOutputStream(zipFile)){using (var streamToZip = new FileStream(fileToZip, FileMode.Open, FileAccess.Read)){var fileName = fileToZip.Substring(fileToZip.LastIndexOf("\", StringComparison.Ordinal) + 1);var zipEntry = new ZipEntry(fileName);zipStream.PutNextEntry(zipEntry);zipStream.SetLevel(compressionLevel);var buffer = new byte[blockSize];try{int sizeRead;do{sizeRead = streamToZip.Read(buffer, 0, buffer.Length);zipStream.Write(buffer, 0, sizeRead);}while (sizeRead > 0);}catch (Exception ex){throw new Exception(ex.Message);}streamToZip.Close();}zipStream.Finish();zipStream.Close();}zipFile.Close();}}catch (IOException ioex){throw new IOException(ioex.Message);}catch (Exception ex){throw new Exception(ex.Message);}}
2. 压缩单个文件:/// <summary>/// 压缩单个文件/// </summary>/// <param name="fileToZip">要进行压缩的文件名</param>/// <param name="zipedFile">压缩后生成的压缩文件名</param>public static void ZipFile(string fileToZip, string zipedFile){if (string.IsNullOrEmpty(fileToZip)){throw new ArgumentException(fileToZip);}if (string.IsNullOrEmpty(zipedFile)){throw new ArgumentException(zipedFile);}if (!File.Exists(fileToZip)){throw new FileNotFoundException("指定要压缩的文件: " + fileToZip + " 不存在!");}try{using (var fs = File.OpenRead(fileToZip)){var buffer = new byte[fs.Length];fs.Read(buffer, 0, buffer.Length);fs.Close();using (var zipFile = File.Create(zipedFile)){using (var zipStream = new ZipOutputStream(zipFile)){var fileName = fileToZip.Substring(fileToZip.LastIndexOf("\", StringComparison.Ordinal) + 1);var zipEntry = new ZipEntry(fileName);zipStream.PutNextEntry(zipEntry);zipStream.SetLevel(5);zipStream.Write(buffer, 0, buffer.Length);zipStream.Finish();zipStream.Close();}}}}catch (IOException ioex){throw new IOException(ioex.Message);}catch (Exception ex){throw new Exception(ex.Message);}}
3.压缩多层目录:
/// <summary>/// 压缩多层目录/// </summary>/// <param name="strDirectory">目录</param>/// <param name="zipedFile">压缩文件</param>public static void ZipFileDirectory(string strDirectory, string zipedFile){if (string.IsNullOrEmpty(strDirectory)){throw new ArgumentException(strDirectory);}if (string.IsNullOrEmpty(zipedFile)){throw new ArgumentException(zipedFile);}using (var zipFile = File.Create(zipedFile)){using (var s = new ZipOutputStream(zipFile)){ZipSetp(strDirectory, s, "");}}}
4.递归遍历目录:
/// <summary>/// 递归遍历目录/// </summary>/// <param name="strDirectory">目录</param>/// <param name="s">ZipOutputStream对象</param>/// <param name="parentPath">父路径</param>private static void ZipSetp(string strDirectory, ZipOutputStream s, string parentPath){if (strDirectory[strDirectory.Length - 1] != Path.DirectorySeparatorChar){strDirectory += Path.DirectorySeparatorChar;}var crc = new Crc32();var filenames = Directory.GetFileSystemEntries(strDirectory);try{// 遍历所有的文件和目录foreach (var file in filenames){// 先当作目录处理如果存在这个目录就递归Copy该目录下面的文件if (Directory.Exists(file)){var pPath = parentPath;pPath += file.Substring(file.LastIndexOf("\", StringComparison.Ordinal) + 1);pPath += "\";ZipSetp(file, s, pPath);}// 否则直接压缩文件else{//打开压缩文件using (var fs = File.OpenRead(file)){var buffer = new byte[fs.Length];fs.Read(buffer, 0, buffer.Length);var fileName = parentPath + file.Substring(file.LastIndexOf("\", StringComparison.Ordinal) + 1);var entry = new ZipEntry(fileName){DateTime = DateTime.Now,Size = fs.Length};fs.Close();crc.Reset();crc.Update(buffer);entry.Crc = crc.Value;s.PutNextEntry(entry);s.Write(buffer, 0, buffer.Length);}}}}catch (IOException ioex){throw new IOException(ioex.Message);}catch (Exception ex){throw new Exception(ex.Message);}}
5.解压缩一个 zip 文件: /// <summary>/// 解压缩一个 zip 文件。/// </summary>/// <param name="zipedFile">The ziped file.</param>/// <param name="strDirectory">The STR directory.</param>/// <param name="password">zip 文件的密码。</param>/// <param name="overWrite">是否覆盖已存在的文件。</param>public void UnZip(string zipedFile, string strDirectory, string password, bool overWrite){if (string.IsNullOrEmpty(zipedFile)){throw new ArgumentException(zipedFile);}if (string.IsNullOrEmpty(strDirectory)){throw new ArgumentException(strDirectory);}if (string.IsNullOrEmpty(password)){throw new ArgumentException(password);}if (strDirectory == ""){strDirectory = Directory.GetCurrentDirectory();}if (!strDirectory.EndsWith("\")){strDirectory = strDirectory + "\";}try{using (var s = new ZipInputStream(File.OpenRead(zipedFile))){s.Password = password;ZipEntry theEntry;while ((theEntry = s.GetNextEntry()) != null){var directoryName = string.Empty;var pathToZip = theEntry.Name;if (pathToZip != ""){directoryName = Path.GetDirectoryName(pathToZip) + "\";}var fileName = Path.GetFileName(pathToZip);Directory.CreateDirectory(strDirectory + directoryName);if (fileName == "") continue;if ((!File.Exists(strDirectory + directoryName + fileName) || !overWrite) &&(File.Exists(strDirectory + directoryName + fileName))) continue;using (var streamWriter = File.Create(strDirectory + directoryName + fileName)){var data = new byte[2048];while (true){var size = s.Read(data, 0, data.Length);if (size > 0)streamWriter.Write(data, 0, size);elsebreak;}streamWriter.Close();}}s.Close();}}catch (IOException ioex){throw new IOException(ioex.Message);}catch (Exception ex){throw new Exception(ex.Message);}}
四.总结:以上是对SharpZipLib组件的相关介绍,本文的讲解上比较的浅显,如果需要深入的学习可以进入官网进行详细的学习。组件的功能是很强大的,如何在项目中使用组件,完成我们在项目中需要实现的功能,这就是对每个开发者提出了要求,需要我们仔细的去考虑。
任何学习都需要我们自己去探索和思考,对于一个开发者来说,最重要的就是思考,因为在我们的职业生涯中,没有什么的重要性能够超过思考。如果有不足之处还望各位读者包含,并留言指正。