在项目开发中,除了对数据的展示更多的就是对文件的相关操作,例如文件的创建和删除,以及文件的压缩和解压。文件压缩的好处有很多,主要就是在文件传输的方面,文件压缩的好处就不需要赘述,因为无论是开发者,还是使用者对于文件压缩的好处都是深有体会。至于文件压缩的原理,在我的另一篇博客中有简单的介绍,在这里就不再做介绍,需要了解的可以查看。

.NET在System.IO.Compression命名空间中提供了GZip、Defalate两种压缩算法。今天我要介绍的一种压缩组件是DotNetZip组件。

一.DotNetZip组件概述:

在DotNetZip的自我介绍中号称是”DotNetZip是.NET最好的开源ZIP库“,至于是不是最好的压缩组件,在这里就不做评价,毕竟每个使用者的心态和工作环境不同,项目对组件的需求也不同,在选择组件的时候,就需要开发者自己衡量了。估计很多人还没有看到这里就开始在键盘上敲字吐槽了,标题是我借用官方对外的宣传口号,不用太在意这些细节。

DotNetZip - Zip和解压缩在C#,VB,任何.NET语言都可使用。DotNetZip是一个FAST,免费类库和用于操纵zip文件的工具集。 使用VB,C#或任何.NET语言轻松创建,解压缩或更新zip文件。DotNetZip在具有完整.NET Framework的PC上运行,并且还在使用.NET Compact Framework的移动设备上运行。在VB,C#或任何.NET语言或任何脚本环境中创建和读取zip文件。

DotNetZip组件的使用环境,毕竟软件的使用环境是每一个开发者都需要考虑的,这个世界没有绝对的好事,当然也没有绝对的坏事。接下来看一下其实用环境的说明吧:

  1.一个动态创建zip文件的Silverlight应用程序。

  2.一个ASP.NET应用程序,动态创建ZIP文件并允许浏览器下载它们。

  3.一个Windows服务,定期地为了备份和归档目的上拉一个目录。

  4.修改现有归档的WPF程序 - 重命名条目,从归档中删除条目或向归档中添加新条目。

  5.一个Windows窗体应用程序,用于为归档内容的隐私创建AES加密的zip存档。

  6.解压缩或拉链的SSIS脚本。

  7.PowerShell或VBScript中的一个管理脚本,用于执行备份和归档。

  8.WCF服务,接收作为附件的zip文件,并动态地将zip解压缩到流以进行分析。

  9.一个老式的ASP(VBScript)应用程序,通过COM接口为DotNetZIp生成一个ZIP文件。

  10.读取或更新ODS文件的Windows Forms应用程序。

  11.从流内容创建zip文件,保存到流,提取到流,从流读取。

  12.创建自解压档案。

DotNetZip是一个100%的托管代码库,可用于任何.NET应用程序 - 控制台,Winforms,WPF,ASP.NET,Sharepoint,Web服务应用程序等。 新的v1.9.1.6:Silverlight。 它还可以从脚本环境或具有COM功能的环境(如Powershell脚本,VBScript,VBA,VB6,PHP,Perl,Javascript等)中使用。 无论使用什么环境,DotNetZip生成的zip文件可与Windows资源管理器以及Java应用程序,在Linux上运行的应用程序完全互操作。

该组件设计简单,易于使用。 DotNetZip打包为一个单一的DLL,大小约400k。 它没有第三方依赖。 它是中等信任,因此可以在大多数托管商使用。 通过引用DLL来获取压缩。 该库支持zip密码,Unicode,ZIP64,流输入和输出,AES加密,多个压缩级别,自解压缩存档,跨区存档等。

以上的一些描述来自与官网,就不再吹捧这个组件了,在这里需要说明的是在组件的选择和使用上,主要取决与项目的实际情况。详情见:http://dotnetzip.codeplex.com/

二.DotNetZip相关核心类和方法解析:

由于下载的是DLL文件,还是采用.NET Reflector对DLL文件进行反编译,以此查看源代码。一下主要介绍一些类和方法,没有完全介绍,首先是由于篇幅所限,其实是完全没有必要,因为对于开发者而言,没有必要全部了解这些类,在实际的开发中,可以根据API进行对应的方法调用,这些技能应该是一个开发人员应该具备的。

1.ZipFile类的AddEntry()、Save()和IsZipFile()方法:

public ZipEntry AddEntry(string entryName, WriteDelegate writer)
{
ZipEntry ze = ZipEntry.CreateForWriter(entryName, writer);
if (this.Verbose)
{
this.StatusMessageTextWriter.WriteLine("adding {0}...", entryName);
}
return this._InternalAddEntry(ze);
}
public void Save()
{
try
{
bool flag = false;
this._saveOperationCanceled = false;
this._numberOfSegmentsForMostRecentSave = ;
this.OnSaveStarted();
if (this.WriteStream == null)
{
throw new BadStateException("You haven't specified where to save the zip.");
}
if (((this._name != null) && this._name.EndsWith(".exe")) && !this._SavingSfx)
{
throw new BadStateException("You specified an EXE for a plain zip file.");
}
if (!this._contentsChanged)
{
this.OnSaveCompleted();
if (this.Verbose)
{
this.StatusMessageTextWriter.WriteLine("No save is necessary....");
}
}
else
{
this.Reset(true);
if (this.Verbose)
{
this.StatusMessageTextWriter.WriteLine("saving....");
}
if ((this._entries.Count >= 0xffff) && (this._zip64 == Zip64Option.Default))
{
throw new ZipException("The number of entries is 65535 or greater. Consider setting the UseZip64WhenSaving property on the ZipFile instance.");
}
int current = ;
ICollection<ZipEntry> entries = this.SortEntriesBeforeSaving ? this.EntriesSorted : this.Entries;
foreach (ZipEntry entry in entries)
{
this.OnSaveEntry(current, entry, true);
entry.Write(this.WriteStream);
if (this._saveOperationCanceled)
{
break;
}
current++;
this.OnSaveEntry(current, entry, false);
if (this._saveOperationCanceled)
{
break;
}
if (entry.IncludedInMostRecentSave)
{
flag |= entry.OutputUsedZip64.Value;
}
}
if (!this._saveOperationCanceled)
{
ZipSegmentedStream writeStream = this.WriteStream as ZipSegmentedStream;
this._numberOfSegmentsForMostRecentSave = (writeStream != null) ? writeStream.CurrentSegment : ;
bool flag2 = ZipOutput.WriteCentralDirectoryStructure(this.WriteStream, entries, this._numberOfSegmentsForMostRecentSave, this._zip64, this.Comment, new ZipContainer(this));
this.OnSaveEvent(ZipProgressEventType.Saving_AfterSaveTempArchive);
this._hasBeenSaved = true;
this._contentsChanged = false;
flag |= flag2;
this._OutputUsesZip64 = new bool?(flag);
if ((this._name != null) && ((this._temporaryFileName != null) || (writeStream != null)))
{
this.WriteStream.Dispose();
if (this._saveOperationCanceled)
{
return;
}
if (this._fileAlreadyExists && (this._readstream != null))
{
this._readstream.Close();
this._readstream = null;
foreach (ZipEntry entry2 in entries)
{
ZipSegmentedStream stream2 = entry2._archiveStream as ZipSegmentedStream;
if (stream2 != null)
{
stream2.Dispose();
}
entry2._archiveStream = null;
}
}
string path = null;
if (File.Exists(this._name))
{
path = this._name + "." + Path.GetRandomFileName();
if (File.Exists(path))
{
this.DeleteFileWithRetry(path);
}
File.Move(this._name, path);
}
this.OnSaveEvent(ZipProgressEventType.Saving_BeforeRenameTempArchive);
File.Move((writeStream != null) ? writeStream.CurrentTempName : this._temporaryFileName, this._name);
this.OnSaveEvent(ZipProgressEventType.Saving_AfterRenameTempArchive);
if (path != null)
{
try
{
if (File.Exists(path))
{
File.Delete(path);
}
}
catch
{
}
}
this._fileAlreadyExists = true;
}
NotifyEntriesSaveComplete(entries);
this.OnSaveCompleted();
this._JustSaved = true;
}
}
}
finally
{
this.CleanupAfterSaveOperation();
}
}
public static bool IsZipFile(Stream stream, bool testExtract)
{
if (stream == null)
{
throw new ArgumentNullException("stream");
}
bool flag = false;
try
{
if (!stream.CanRead)
{
return false;
}
Stream @null = Stream.Null;
using (ZipFile file = Read(stream, null, null, null))
{
if (testExtract)
{
foreach (ZipEntry entry in file)
{
if (!entry.IsDirectory)
{
entry.Extract(@null);
}
}
}
}
flag = true;
}
catch (IOException)
{
}
catch (ZipException)
{
}
return flag;
}

2.Read()读取数据流:

private static ZipFile Read(Stream zipStream, TextWriter statusMessageWriter, Encoding encoding, EventHandler<ReadProgressEventArgs> readProgress)
{
if (zipStream == null)
{
throw new ArgumentNullException("zipStream");
}
ZipFile zf = new ZipFile {
_StatusMessageTextWriter = statusMessageWriter,
_alternateEncoding = encoding ?? DefaultEncoding,
_alternateEncodingUsage = ZipOption.Always
};
if (readProgress != null)
{
zf.ReadProgress += readProgress;
}
zf._readstream = (zipStream.Position == 0L) ? zipStream : new OffsetStream(zipStream);
zf._ReadStreamIsOurs = false;
if (zf.Verbose)
{
zf._StatusMessageTextWriter.WriteLine("reading from stream...");
}
ReadIntoInstance(zf);
return zf;
}

以上是对ZipFile类的一些方法的解析,提供了该组件的一些方法的源码,至于源码的解读上难度不是很大,至于该组件的API,可以在下载DLL文件后,可以直接查看相应的方法和属性,在这里就不做详细的介绍。

三.DotNetZip组件使用实例:

以上是对该组件的一些解析,接下来我们看看实例:

1.压缩ZIP文件:

        /// <summary>
/// 压缩ZIP文件
/// 支持多文件和多目录,或是多文件和多目录一起压缩
/// </summary>
/// <param name="list">待压缩的文件或目录集合</param>
/// <param name="strZipName">压缩后的文件名</param>
/// <param name="isDirStruct">是否按目录结构压缩</param>
/// <returns>成功:true/失败:false</returns>
public static bool CompressMulti(List<string> list, string strZipName, bool isDirStruct)
{
if (list == null)
{
throw new ArgumentNullException("list");
}
if (string.IsNullOrEmpty(strZipName))
{
throw new ArgumentNullException(strZipName);
}
try
{
//设置编码,解决压缩文件时中文乱码
using (var zip = new ZipFile(Encoding.Default))
{
foreach (var path in list)
{
//取目录名称
var fileName = Path.GetFileName(path);
//如果是目录
if (Directory.Exists(path))
{
//按目录结构压缩
if (isDirStruct)
{
zip.AddDirectory(path, fileName);
}
else
{
//目录下的文件都压缩到Zip的根目录
zip.AddDirectory(path);
}
}
if (File.Exists(path))
{
zip.AddFile(path);
}
}
//压缩
zip.Save(strZipName);
return true;
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}

2.解压ZIP文件:

        /// <summary>
/// 解压ZIP文件
/// </summary>
/// <param name="strZipPath">待解压的ZIP文件</param>
/// <param name="strUnZipPath">解压的目录</param>
/// <param name="overWrite">是否覆盖</param>
/// <returns>成功:true/失败:false</returns>
public static bool Decompression(string strZipPath, string strUnZipPath, bool overWrite)
{
if (string.IsNullOrEmpty(strZipPath))
{
throw new ArgumentNullException(strZipPath);
}
if (string.IsNullOrEmpty(strUnZipPath))
{
throw new ArgumentNullException(strUnZipPath);
}
try
{
var options = new ReadOptions
{
Encoding = Encoding.Default
};
//设置编码,解决解压文件时中文乱码
using (var zip = ZipFile.Read(strZipPath, options))
{
foreach (var entry in zip)
{
if (string.IsNullOrEmpty(strUnZipPath))
{
strUnZipPath = strZipPath.Split('.').First();
}
entry.Extract(strUnZipPath,overWrite
? ExtractExistingFileAction.OverwriteSilently
: ExtractExistingFileAction.DoNotOverwrite);
}
return true;
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}

3.得到指定的输入流的ZIP压缩流对象:

        /// <summary>
/// 得到指定的输入流的ZIP压缩流对象
/// </summary>
/// <param name="sourceStream">源数据流</param>
/// <param name="entryName">实体名称</param>
/// <returns></returns>
public static Stream ZipCompress(Stream sourceStream, string entryName = "zip")
{
if (sourceStream == null)
{
throw new ArgumentNullException("sourceStream");
}
var compressedStream = new MemoryStream();
long sourceOldPosition = ;
try
{
sourceOldPosition = sourceStream.Position;
sourceStream.Position = ;
using (var zip = new ZipFile())
{
zip.AddEntry(entryName, sourceStream);
zip.Save(compressedStream);
compressedStream.Position = ;
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
finally
{
try
{
sourceStream.Position = sourceOldPosition;
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
return compressedStream;
}

4.得到指定的字节数组的ZIP解压流对象:

        /// <summary>
/// 得到指定的字节数组的ZIP解压流对象
/// 当前方法仅适用于只有一个压缩文件的压缩包,即方法内只取压缩包中的第一个压缩文件
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public static Stream ZipDecompress(byte[] data)
{
Stream decompressedStream = new MemoryStream();
if (data == null) return decompressedStream;
try
{
var dataStream = new MemoryStream(data);
using (var zip = ZipFile.Read(dataStream))
{
if (zip.Entries.Count > )
{
zip.Entries.First().Extract(decompressedStream);
// Extract方法中会操作ms,后续使用时必须先将Stream位置归零,否则会导致后续读取不到任何数据
// 返回该Stream对象之前进行一次位置归零动作
decompressedStream.Position = ;
}
}
}
catch(Exception ex)
{
throw new Exception(ex.Message);
}
return decompressedStream;
}

四.总结:

以上是对DotNetZip组件的一些解析和方法实例,至于这款组件是不是最好的.NET压缩组件,这个就不做评价。个人在选择组件的时候,首先考虑的是开源,其次是免费,最后再考虑效率和实用性,毕竟在国内的一些情况是所有开发者都清楚的(不提国外是由于我不知道国外的情况)。客户需要降低成本,并且组件要可以进行定制。不过个人认为收费应该是一种趋势,毕竟所有的产品都是需要人员进行维护和开发。以上的博文中有不足之处,还望多多指正。

.NET组件介绍系列:

一款开源免费的.NET文档操作组件DocX(.NET组件介绍之一)http://www.cnblogs.com/pengze0902/p/6122311.html

高效而稳定的企业级.NET Office 组件Spire(.NET组件介绍之二)http://www.cnblogs.com/pengze0902/p/6125570.html

最好的.NET开源免费ZIP库DotNetZip(.NET组件介绍之三)http://www.cnblogs.com/pengze0902/p/6124659.html

免费开源的DotNet二维码操作组件ThoughtWorks.QRCode(.NET组件介绍之四)http://www.cnblogs.com/pengze0902/p/6134506.html

免费开源的DotNet任务调度组件Quartz.NET(.NET组件介绍之五)http://www.cnblogs.com/pengze0902/p/6128558.html

免费高效实用的Excel操作组件NPOI(.NET组件介绍之六)http://www.cnblogs.com/pengze0902/p/6150070.html

最好的.NET开源免费ZIP库DotNetZip(.NET组件介绍之三)的更多相关文章

  1. Blazor Bootstrap 组件库浏览器通知组件介绍

    通知组件 通过浏览器API发送通知信息 , 桌面浏览器表现为右下角系统提示框弹出消息, 移动浏览器表现为弹窗或者到消息列表, blazor页面不在前台也可以通过本组件提醒用户. DEMO https: ...

  2. 开源免费且稳定实用的.NET PDF打印组件itextSharp(.NET组件介绍之八)

    在这个.NET组件的介绍系列中,受到了很多园友的支持,一些园友(如:数据之巅. [秦时明月]等等这些大神 )也给我提出了对应的建议,我正在努力去改正,有不足之处还望大家多多包涵.在传播一些简单的知识的 ...

  3. 免费开源的.NET多类型文件解压缩组件SharpZipLib(.NET组件介绍之七)

    前面介绍了六种.NET组件,其中有一种组件是写文件的压缩和解压,现在介绍另一种文件的解压缩组件SharpZipLib.在这个组件介绍系列中,只为简单的介绍组件的背景和简单的应用,读者在阅读时可以结合官 ...

  4. 免费开源的DotNet任务调度组件Quartz.NET(.NET组件介绍之五)

    很多的软件项目中都会使用到定时任务.定时轮询数据库同步,定时邮件通知等功能..NET Framework具有“内置”定时器功能,通过System.Timers.Timer类.在使用Timer类需要面对 ...

  5. 免费开源的DotNet二维码操作组件ThoughtWorks.QRCode(.NET组件介绍之四)

    在生活中有一种东西几乎已经快要成为我们的另一个电子”身份证“,那就是二维码.无论是在软件开发的过程中,还是在普通用户的日常中,几乎都离不开二维码.二维码 (dimensional barcode) , ...

  6. 一款开源免费的.NET文档操作组件DocX(.NET组件介绍之一)

    在目前的软件项目中,都会较多的使用到对文档的操作,用于记录和统计相关业务信息.由于系统自身提供了对文档的相关操作,所以在一定程度上极大的简化了软件使用者的工作量. 在.NET项目中如果用户提出了相关文 ...

  7. 免费高效实用的.NET操作Excel组件NPOI(.NET组件介绍之六)

    很多的软件项目几乎都包含着对文档的操作,前面已经介绍过两款操作文档的组件,现在介绍一款文档操作的组件NPOI. NPOI可以生成没有安装在您的服务器上的Microsoft Office套件的Excel ...

  8. vs2015下编译免费开源的jpeg库,ijg的jpeg.lib

    vs2015下编译免费开源的jpeg库,ijg的jpeg.lib 1. 去Independent JPEG Group官网www.ijg.org下载jpegsrc,我下载的版本是jpegsrc9c.z ...

  9. .NET 开源免费图表组件库,Winform,WPF 通用

    大家好, 我是等天黑, 今天给大家介绍一个功能完善, 性能强悍的图表组件库 ScottPlot, 当我第一次在 github 上看到这个库, 我看不懂,但我大受震撼, 这么好的项目当然要分享出来了. ...

随机推荐

  1. 如何一步一步用DDD设计一个电商网站(八)—— 会员价的集成

    阅读目录 前言 建模 实现 结语 一.前言 前面几篇已经实现了一个基本的购买+售价计算的过程,这次再让售价丰满一些,增加一个会员价的概念.会员价在现在的主流电商中,是一个不大常见的模式,其带来的问题是 ...

  2. 梅须逊雪三分白,雪却输梅一段香——CSS动画与JavaScript动画

    CSS动画并不是绝对比JavaScript动画性能更优越,开源动画库Velocity.js等就展现了强劲的性能. 一.两者的主要区别 先开门见山的说说两者之间的区别. 1)CSS动画: 基于CSS的动 ...

  3. FFmpeg学习6:视音频同步

    在上一篇文章中,视频和音频是各自独立播放的,并不同步.本文主要描述了如何以音频的播放时长为基准,将视频同步到音频上以实现视音频的同步播放的.主要有以下几个方面的内容 视音频同步的简单介绍 DTS 和 ...

  4. [Spring]IoC容器之进击的注解

    先啰嗦两句: 第一次在博客园使用markdown编辑,感觉渲染样式差强人意,还是github的样式比较顺眼. 概述 Spring2.5 引入了注解. 于是,一个问题产生了:使用注解方式注入 JavaB ...

  5. UWP中实现自定义标题栏

    UWP中实现自定义标题栏 0x00 起因 在UWP开发中,有时候我们希望实现自定义标题栏,例如在标题栏中加入搜索框.按钮之类的控件.搜了下资料居然在一个日文网站找到了一篇介绍这个主题的文章: http ...

  6. 使用 .NET WinForm 开发所见即所得的 IDE 开发环境,实现不写代码直接生成应用程序

    直接切入正题,这是我09年到11年左右业余时间编写的项目,最初的想法很简单,做一个能拖拖拽拽就直接生成应用程序的工具,不用写代码,把能想到的业务操作全部封装起来,通过配置的方式把这些业务操作组织起来运 ...

  7. C语言 · 薪水计算

    问题描述 编写一个程序,计算员工的周薪.薪水的计算是以小时为单位,如果在一周的时间内,员工工作的时间不超过40 个小时,那么他/她的总收入等于工作时间乘以每小时的薪水.如果员工工作的时间在40 到50 ...

  8. 了解PHP中的Array数组和foreach

    1. 了解数组 PHP 中的数组实际上是一个有序映射.映射是一种把 values 关联到 keys 的类型.详细的解释可参见:PHP.net中的Array数组    . 2.例子:一般的数组 这里,我 ...

  9. 隐马尔科夫模型python实现简单拼音输入法

    在网上看到一篇关于隐马尔科夫模型的介绍,觉得简直不能再神奇,又在网上找到大神的一篇关于如何用隐马尔可夫模型实现中文拼音输入的博客,无奈大神没给可以运行的代码,只能纯手动网上找到了结巴分词的词库,根据此 ...

  10. [原] KVM 虚拟化原理探究(6)— 块设备IO虚拟化

    KVM 虚拟化原理探究(6)- 块设备IO虚拟化 标签(空格分隔): KVM [toc] 块设备IO虚拟化简介 上一篇文章讲到了网络IO虚拟化,作为另外一个重要的虚拟化资源,块设备IO的虚拟化也是同样 ...