gpt4 book ai didi

详解最好的.NET开源免费ZIP库DotNetZip(.NET组件介绍之三)

转载 作者:qq735679552 更新时间:2022-09-29 22:32:09 24 4
gpt4 key购买 nike

CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.

这篇CFSDN的博客文章详解最好的.NET开源免费ZIP库DotNetZip(.NET组件介绍之三)由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.

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

 .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()方法:

?
1
2
3
4
5
6
7
8
9
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);
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
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();
  }
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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()读取数据流:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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文件:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/// <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文件:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/// <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压缩流对象:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/// <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;
   }

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/// <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压缩组件,这个就不做评价。个人在选择组件的时候,首先考虑的是开源,其次是免费,最后再考虑效率和实用性,毕竟在国内的一些情况是所有开发者都清楚的(不提国外是由于我不知道国外的情况)。客户需要降低成本,并且组件要可以进行定制。不过个人认为收费应该是一种趋势,毕竟所有的产品都是需要人员进行维护和开发。以上的博文中有不足之处,还望多多指正.

原文链接:http://www.cnblogs.com/pengze0902/p/6124659.html 。

最后此篇关于详解最好的.NET开源免费ZIP库DotNetZip(.NET组件介绍之三)的文章就讲到这里了,如果你想了解更多关于详解最好的.NET开源免费ZIP库DotNetZip(.NET组件介绍之三)的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com