详解免费开源的.NET多类型文件解压缩组件SharpZipLib(.NET组件介绍之七)
前面介绍了六种.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); else break; } streamWriter.Close(); } } s.Close(); } } catch (IOException ioex) { throw new IOException(ioex.Message); } catch (Exception ex) { throw new Exception(ex.Message); } }
四.总结:
以上是对SharpZipLib组件的相关介绍,本文的讲解上比较的浅显,如果需要深入的学习可以进入官网进行详细的学习。组件的功能是很强大的,如何在项目中使用组件,完成我们在项目中需要实现的功能,这就是对每个开发者提出了要求,需要我们仔细的去考虑。
任何学习都需要我们自己去探索和思考,对于一个开发者来说,最重要的就是思考,因为在我们的职业生涯中,没有什么的重要性能够超过思考。如果有不足之处还望各位读者包含,并留言指正。
相关文章
- 这篇文章主要为大家详细介绍了ASP.NET购物车的实现过程,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-09-22
- 这篇文章主要介绍了.NET Core下使用Kafka的方法步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-09-22
- 在开发过程中,使用Visual Studio的断点调试功能可以很方便帮我们调试发现程序存在的错误,同样Visual Studio也支持对SQL Server里面的存储过程进行调试,下面就让我们看看具体的调试方法。...2021-09-22
- 这篇文章主要介绍了Win10 IIS 安装及.net 4.5及Win10安装IIS并配置ASP.NET 4.0的方法,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下...2021-09-22
- 这篇文章主要介绍了详解.NET Core 3.0 里新的JSON API,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-09-22
- 这篇文章主要介绍了.net数据库操作框架SqlSugar的简单入门,帮助大家更好的理解和学习使用.net技术,感兴趣的朋友可以了解下...2021-09-22
ASP.NET Core根据环境变量支持多个 appsettings.json配置文件
这篇文章主要介绍了ASP.NET Core根据环境变量支持多个 appsettings.json配置文件,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-09-22- 这篇文章主要介绍了记一次EFCore类型转换错误及解决方案,帮助大家更好的理解和学习使用asp.net core,感兴趣的朋友可以了解下...2021-09-22
详解ASP.NET Core 中基于工厂的中间件激活的实现方法
这篇文章主要介绍了ASP.NET Core 中基于工厂的中间件激活的实现方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-09-22- 这篇文章主要介绍了C#使用Ado.Net更新和添加数据到Excel表格的方法,较为详细的分析了OLEDB的原理与使用技巧,可实现较为方便的操作Excel数据,需要的朋友可以参考下...2020-06-25
- ZXing是一个开放源码的,用Java实现的多种格式的1D/2D条码图像处理库,它包含了联系到其他语言的端口。这篇文章主要给大家介绍了.NET C#利用ZXing生成、识别二维码/条形码的方法,文中给出了详细的示例代码,有需要的朋友们可以参考借鉴。...2020-06-25
asp.net通过消息队列处理高并发请求(以抢小米手机为例)
这篇文章主要介绍了asp.net通过消息队列处理高并发请求(以抢小米手机为例),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-09-22ASP.NET单选按钮控件RadioButton常用属性和方法介绍
RadioButton又称单选按钮,其在工具箱中的图标为 ,单选按钮通常成组出现,用于提供两个或多个互斥选项,即在一组单选钮中只能选择一个...2021-09-22ASP.NET 2.0中的数据操作:使用两个DropDownList过滤的主/从报表
在前面的指南中我们研究了如何显示一个简单的主/从报表, 该报表使用DropDownList和GridView控件, DropDownList填充类别,GridView显示选定类别的产品. 这类报表用于显示具有...2016-05-19详解.NET Core 使用HttpClient SSL请求出错的解决办法
这篇文章主要介绍了.NET Core 使用HttpClient SSL请求出错的解决办法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2021-09-22- 这篇文章主要介绍了Python调用.NET库的方法步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-05-09
ASP.NET中iframe框架点击左边页面链接 右边显示链接页面内容
这篇文章主要介绍了ASP.NET中iframe框架点击左边页面链接,右边显示链接页面内容的实现代码,感兴趣的小伙伴们可以参考一下...2021-09-22- ASP.NET Web API具有与ASP.NET MVC类似的编程方式,ASP.NET Web API不仅仅具有一个完全独立的消息处理管道,而且这个管道比为ASP.NET MVC设计的管道更为复杂,功能也更为强大。下面创建一个简单的Web API项目,需要的朋友可以参考下...2021-09-22
- 这篇文章主要介绍了ASP.NET连接MySql数据库的2个方法及示例,使用的是MySQL官方组件和ODBC.NET,需要的朋友可以参考下...2021-09-22
C# 利用ICSharpCode.SharpZipLib实现在线压缩和解压缩
本文主要主要介绍了利用ICSharpCode.SharpZipLib第三方的DLL库实现在线压缩和解压缩的功能,并做了相关的代码演示。...2020-06-25