C#压缩库SharpZipLib的应用

   SharpZipLib是一个开源的C#压缩解压库,应用非常广泛。就像用ADO.NET操作数据库要打开连接、执行命令、关闭连接等多个步骤一样,用SharpZipLib进行压缩和解压也需要多个步骤。除了初学者会用原始的方法做一步一步完成,实际开发的时候都会进行更易用的封装。这里分享我对SharpZipLib的封装,支持对文件和字节进行压缩和解压操作,支持多个文件和文件夹压缩,支持设置备注和密码。(文章源网址:http://www.cnblogs.com/conexpress/p/SharpZipClass.html)
    SharpZipLib的官方地址是:http://icsharpcode.github.io/SharpZipLib/,实际使用可以通过NuGet获取,在NuGet的地址是:http://www.nuget.org/packages/SharpZipLib/
SharpZipLib_NuGet
 
在Visual Studio中可以通过NuGet程序包管理控制台输入命令PM> Install-Package SharpZipLib或者用NuGet管理界面搜索并安装。
我把使用SharpZipLib的方法卸载一个类里面,作为静态方法调用,免去创建类的麻烦。其中核心压缩和解压文件的方法代码如下:
  1         /// <summary>
  2         /// 压缩多个文件/文件夹
  3         /// </summary>
  4         /// <param name="sourceList">源文件/文件夹路径列表</param>
  5         /// <param name="zipFilePath">压缩文件路径</param>
  6         /// <param name="comment">注释信息</param>
  7         /// <param name="password">压缩密码</param>
  8         /// <param name="compressionLevel">压缩等级,范围从0到9,可选,默认为6</param>
  9         /// <returns></returns>
 10         public static bool CompressFile(IEnumerable<string> sourceList, string zipFilePath,
 11              string comment = null, string password = null, int compressionLevel = 6)
 12         {
 13             bool result = false;
 14 
 15             try
 16             {
 17                 //检测目标文件所属的文件夹是否存在,如果不存在则建立
 18                 string zipFileDirectory = Path.GetDirectoryName(zipFilePath);
 19                 if (!Directory.Exists(zipFileDirectory))
 20                 {
 21                     Directory.CreateDirectory(zipFileDirectory);
 22                 }
 23 
 24                 Dictionary<string, string> dictionaryList = PrepareFileSystementities(sourceList);
 25 
 26                 using (ZipOutputStream zipStream = new ZipOutputStream(File.Create(zipFilePath)))
 27                 {
 28                     zipStream.Password = password;//设置密码
 29                     zipStream.SetComment(comment);//添加注释
 30                     zipStream.SetLevel(CheckCompressionLevel(compressionLevel));//设置压缩等级
 31 
 32                     foreach (string key in dictionaryList.Keys)//从字典取文件添加到压缩文件
 33                     {
 34                         if (File.Exists(key))//判断是文件还是文件夹
 35                         {
 36                             FileInfo fileItem = new FileInfo(key);
 37 
 38                             using (FileStream readStream = fileItem.Open(FileMode.Open,
 39                                 FileAccess.Read, FileShare.Read))
 40                             {
 41                                 ZipEntry zipEntry = new ZipEntry(dictionaryList[key]);
 42                                 zipEntry.DateTime = fileItem.LastWriteTime;
 43                                 zipEntry.Size = readStream.Length;
 44                                 zipStream.PutNextEntry(zipEntry);
 45                                 int readLength = 0;
 46                                 byte[] buffer = new byte[BufferSize];
 47 
 48                                 do
 49                                 {
 50                                     readLength = readStream.Read(buffer, 0, BufferSize);
 51                                     zipStream.Write(buffer, 0, readLength);
 52                                 } while (readLength == BufferSize);
 53 
 54                                 readStream.Close();
 55                             }
 56                         }
 57                         else//对文件夹的处理
 58                         {
 59                             ZipEntry zipEntry = new ZipEntry(dictionaryList[key] + "/");
 60                             zipStream.PutNextEntry(zipEntry);
 61                         }
 62                     }
 63 
 64                     zipStream.Flush();
 65                     zipStream.Finish();
 66                     zipStream.Close();
 67                 }
 68 
 69                 result = true;
 70             }
 71             catch (System.Exception ex)
 72             {
 73                 throw new Exception("压缩文件失败", ex);
 74             }
 75 
 76             return result;
 77         }
 78 
 79         /// <summary>
 80         /// 解压文件到指定文件夹
 81         /// </summary>
 82         /// <param name="sourceFile">压缩文件</param>
 83         /// <param name="destinationDirectory">目标文件夹,如果为空则解压到当前文件夹下</param>
 84         /// <param name="password">密码</param>
 85         /// <returns></returns>
 86         public static bool DecomparessFile(string sourceFile, string destinationDirectory = null, string password = null)
 87         {
 88             bool result = false;
 89 
 90             if (!File.Exists(sourceFile))
 91             {
 92                 throw new FileNotFoundException("要解压的文件不存在", sourceFile);
 93             }
 94 
 95             if (string.IsNullOrWhiteSpace(destinationDirectory))
 96             {
 97                 destinationDirectory = Path.GetDirectoryName(sourceFile);
 98             }
 99 
100             try
101             {
102                 if (!Directory.Exists(destinationDirectory))
103                 {
104                     Directory.CreateDirectory(destinationDirectory);
105                 }
106 
107                 using (ZipInputStream zipStream = new ZipInputStream(File.Open(sourceFile, FileMode.Open,
108                     FileAccess.Read, FileShare.Read)))
109                 {
110                     zipStream.Password = password;
111                     ZipEntry zipEntry = zipStream.GetNextEntry();
112 
113                     while (zipEntry != null)
114                     {
115                         if (zipEntry.IsDirectory)//如果是文件夹则创建
116                         {
117                             Directory.CreateDirectory(Path.Combine(destinationDirectory,
118                                 Path.GetDirectoryName(zipEntry.Name)));
119                         }
120                         else
121                         {
122                             string fileName = Path.GetFileName(zipEntry.Name);
123                             if (!string.IsNullOrEmpty(fileName) && fileName.Trim().Length > 0)
124                             {
125                                 FileInfo fileItem = new FileInfo(Path.Combine(destinationDirectory, zipEntry.Name));
126                                 using (FileStream writeStream = fileItem.Create())
127                                 {
128                                     byte[] buffer = new byte[BufferSize];
129                                     int readLength = 0;
130 
131                                     do
132                                     {
133                                         readLength = zipStream.Read(buffer, 0, BufferSize);
134                                         writeStream.Write(buffer, 0, readLength);
135                                     } while (readLength == BufferSize);
136 
137                                     writeStream.Flush();
138                                     writeStream.Close();
139                                 }
140                                 fileItem.LastWriteTime = zipEntry.DateTime;
141                             }
142                         }
143                         zipEntry = zipStream.GetNextEntry();//获取下一个文件
144                     }
145 
146                     zipStream.Close();
147                 }
148                 result = true;
149             }
150             catch (System.Exception ex)
151             {
152                 throw new Exception("文件解压发生错误", ex);
153             }
154 
155             return result;
156         }
压缩方法CompressFile中sourceList是路径数组,支持文件夹和文件的路径。当遇到文件夹时会自动将下级文件和文件夹包含,并会检测重复项。文件路径处理的方法如下:
 1         /// <summary>
 2         /// 为压缩准备文件系统对象
 3         /// </summary>
 4         /// <param name="sourceFileEntityPathList"></param>
 5         /// <returns></returns>
 6         private static Dictionary<string, string> PrepareFileSystementities(IEnumerable<string> sourceFileEntityPathList)
 7         {
 8             Dictionary<string, string> fileEntityDictionary = new Dictionary<string, string>();//文件字典
 9             string parentDirectoryPath = "";
10             foreach (string fileEntityPath in sourceFileEntityPathList)
11             {
12                 string path = fileEntityPath;
13                 //保证传入的文件夹也被压缩进文件
14                 if (path.EndsWith(@"\"))
15                 {
16                     path = path.Remove(path.LastIndexOf(@"\"));
17                 }
18 
19                 parentDirectoryPath = Path.GetDirectoryName(path) + @"\";
20 
21                 if (parentDirectoryPath.EndsWith(@":\\"))//防止根目录下把盘符压入的错误
22                 {
23                     parentDirectoryPath = parentDirectoryPath.Replace(@"\\", @"\");
24                 }
25 
26                 //获取目录中所有的文件系统对象
27                 Dictionary<string, string> subDictionary = GetAllFileSystemEntities(path, parentDirectoryPath);
28 
29                 //将文件系统对象添加到总的文件字典中
30                 foreach (string key in subDictionary.Keys)
31                 {
32                     if (!fileEntityDictionary.ContainsKey(key))//检测重复项
33                     {
34                         fileEntityDictionary.Add(key, subDictionary[key]);
35                     }
36                 }
37             }
38             return fileEntityDictionary;
39         }
40 
41         /// <summary>
42         /// 获取所有文件系统对象
43         /// </summary>
44         /// <param name="source">源路径</param>
45         /// <param name="topDirectory">顶级文件夹</param>
46         /// <returns>字典中Key为完整路径,Value为文件(夹)名称</returns>
47         private static Dictionary<string, string> GetAllFileSystemEntities(string source, string topDirectory)
48         {
49             Dictionary<string, string> entitiesDictionary = new Dictionary<string, string>();
50             entitiesDictionary.Add(source, source.Replace(topDirectory, ""));
51 
52             if (Directory.Exists(source))
53             {
54                 //一次性获取下级所有目录,避免递归
55                 string[] directories = Directory.GetDirectories(source, "*.*", SearchOption.AllDirectories);
56                 foreach (string directory in directories)
57                 {
58                     entitiesDictionary.Add(directory, directory.Replace(topDirectory, ""));
59                 }
60 
61                 string[] files = Directory.GetFiles(source, "*.*", SearchOption.AllDirectories);
62                 foreach (string file in files)
63                 {
64                     entitiesDictionary.Add(file, file.Replace(topDirectory, ""));
65                 }
66             }
67 
68             return entitiesDictionary;
69         }

除了支持文件和文件夹压缩解压,还提供了对字节的压缩解压方法:

  1         /// <summary>
  2         /// 压缩字节数组
  3         /// </summary>
  4         /// <param name="sourceBytes">源字节数组</param>
  5         /// <param name="compressionLevel">压缩等级</param>
  6         /// <param name="password">密码</param>
  7         /// <returns>压缩后的字节数组</returns>
  8         public static byte[] CompressBytes(byte[] sourceBytes, string password = null, int compressionLevel = 6)
  9         {
 10             byte[] result = new byte[] { };
 11 
 12             if (sourceBytes.Length > 0)
 13             {
 14                 try
 15                 {
 16                     using (MemoryStream tempStream = new MemoryStream())
 17                     {
 18                         using (MemoryStream readStream = new MemoryStream(sourceBytes))
 19                         {
 20                             using (ZipOutputStream zipStream = new ZipOutputStream(tempStream))
 21                             {
 22                                 zipStream.Password = password;//设置密码
 23                                 zipStream.SetLevel(CheckCompressionLevel(compressionLevel));//设置压缩等级
 24 
 25                                 ZipEntry zipEntry = new ZipEntry("ZipBytes");
 26                                 zipEntry.DateTime = DateTime.Now;
 27                                 zipEntry.Size = sourceBytes.Length;
 28                                 zipStream.PutNextEntry(zipEntry);
 29                                 int readLength = 0;
 30                                 byte[] buffer = new byte[BufferSize];
 31 
 32                                 do
 33                                 {
 34                                     readLength = readStream.Read(buffer, 0, BufferSize);
 35                                     zipStream.Write(buffer, 0, readLength);
 36                                 } while (readLength == BufferSize);
 37 
 38                                 readStream.Close();
 39                                 zipStream.Flush();
 40                                 zipStream.Finish();
 41                                 result = tempStream.ToArray();
 42                                 zipStream.Close();
 43                             }
 44                         }
 45                     }
 46                 }
 47                 catch (System.Exception ex)
 48                 {
 49                     throw new Exception("压缩字节数组发生错误", ex);
 50                 }
 51             }
 52 
 53             return result;
 54         }
 55 
 56         /// <summary>
 57         /// 解压字节数组
 58         /// </summary>
 59         /// <param name="sourceBytes">源字节数组</param>
 60         /// <param name="password">密码</param>
 61         /// <returns>解压后的字节数组</returns>
 62         public static byte[] DecompressBytes(byte[] sourceBytes, string password = null)
 63         {
 64             byte[] result = new byte[] { };
 65 
 66             if (sourceBytes.Length > 0)
 67             {
 68                 try
 69                 {
 70                     using (MemoryStream tempStream = new MemoryStream(sourceBytes))
 71                     {
 72                         using (MemoryStream writeStream = new MemoryStream())
 73                         {
 74                             using (ZipInputStream zipStream = new ZipInputStream(tempStream))
 75                             {
 76                                 zipStream.Password = password;
 77                                 ZipEntry zipEntry = zipStream.GetNextEntry();
 78 
 79                                 if (zipEntry != null)
 80                                 {
 81                                     byte[] buffer = new byte[BufferSize];
 82                                     int readLength = 0;
 83 
 84                                     do
 85                                     {
 86                                         readLength = zipStream.Read(buffer, 0, BufferSize);
 87                                         writeStream.Write(buffer, 0, readLength);
 88                                     } while (readLength == BufferSize);
 89 
 90                                     writeStream.Flush();
 91                                     result = writeStream.ToArray();
 92                                     writeStream.Close();
 93                                 }
 94                                 zipStream.Close();
 95                             }
 96                         }
 97                     }
 98                 }
 99                 catch (System.Exception ex)
100                 {
101                     throw new Exception("解压字节数组发生错误", ex);
102                 }
103             }
104             return result;
105         }
View Code

为了测试该类,我写了一个WinForm程序,界面如下:

SharpZipLib测试界面
可以将文件和文件夹拖放到压缩列表中,选中压缩列表中的对象可以按Delete键进行删除。文件解压区域也可以将要解压的文件拖放到文件路径输入文本框。实际测试可以正确压缩和解压,包括设置密码,压缩和解压操作和WinRAR完全兼容。如果您在代码中发现问题或有可以优化完善的地方,欢迎指出,谢谢!
程序源代码下载:https://files.cnblogs.com/files/conexpress/SharpZipTest.zip
 
posted @ 2016-08-25 12:03  Alex Leo  阅读(12998)  评论(3编辑  收藏  举报