在项目开发中,除了对数据的展现更多的就是对文件的相关操做,例如文件的建立和删除,以及文件的压缩和解压。文件压缩的好处有不少,主要就是在文件传输的方面,文件压缩的好处就不须要赘述,由于不管是开发者,仍是使用者对于文件压缩的好处都是深有体会。至于文件压缩的原理,在个人另外一篇博客中有简单的介绍,在这里就再也不作介绍,须要了解的能够查看。html
.NET在System.IO.Compression命名空间中提供了GZip、Defalate两种压缩算法。今天我要介绍的一种压缩组件是DotNetZip组件。算法
在DotNetZip的自我介绍中号称是”DotNetZip是.NET最好的开源ZIP库“,至因而不是最好的压缩组件,在这里就不作评价,毕竟每一个使用者的心态和工做环境不一样,项目对组件的需求也不一样,在选择组件的时候,就须要开发者本身衡量了。估计不少人尚未看到这里就开始在键盘上敲字吐槽了,标题是我借用官方对外的宣传口号,不用太在乎这些细节。shell
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应用程序。dom
2.一个ASP.NET应用程序,动态建立ZIP文件并容许浏览器下载它们。ide
3.一个Windows服务,按期地为了备份和归档目的上拉一个目录。工具
4.修改现有归档的WPF程序 - 重命名条目,从归档中删除条目或向归档中添加新条目。post
5.一个Windows窗体应用程序,用于为归档内容的隐私建立AES加密的zip存档。this
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/
因为下载的是DLL文件,仍是采用.NET Reflector对DLL文件进行反编译,以此查看源代码。一下主要介绍一些类和方法,没有彻底介绍,首先是因为篇幅所限,实际上是彻底没有必要,由于对于开发者而言,没有必要所有了解这些类,在实际的开发中,能够根据API进行对应的方法调用,这些技能应该是一个开发人员应该具有的。
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 = 0; 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 = 0; 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 : 1; 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; }
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文件后,能够直接查看相应的方法和属性,在这里就不作详细的介绍。
以上是对该组件的一些解析,接下来咱们看看实例:
/// <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); } }
/// <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); } }
/// <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 = 0; try { sourceOldPosition = sourceStream.Position; sourceStream.Position = 0; using (var zip = new ZipFile()) { zip.AddEntry(entryName, sourceStream); zip.Save(compressedStream); compressedStream.Position = 0; } } catch (Exception ex) { throw new Exception(ex.Message); } finally { try { sourceStream.Position = sourceOldPosition; } catch (Exception ex) { throw new Exception(ex.Message); } } return compressedStream; }
/// <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 > 0) { zip.Entries.First().Extract(decompressedStream); // Extract方法中会操做ms,后续使用时必须先将Stream位置归零,不然会致使后续读取不到任何数据 // 返回该Stream对象以前进行一次位置归零动做 decompressedStream.Position = 0; } } } catch(Exception ex) { throw new Exception(ex.Message); } return decompressedStream; }
以上是对DotNetZip组件的一些解析和方法实例,至于这款组件是否是最好的.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