你的位置:首页 > ASP.net教程

[ASP.net教程]压缩库SharpZipLib的应用


   SharpZipLib是一个开源的C#压缩解压库,应用非常广泛。就像用ADO.NET操作数据库要打开连接、执行命令、关闭连接等多个步骤一样,用SharpZipLib进行压缩和解压也需要多个步骤。除了初学者会用原始的方法做一步一步完成,实际开发的时候都会进行更易用的封装。这里分享我对SharpZipLib的封装,支持对文件和流进行压缩和解压操作,支持多个文件和文件夹压缩,支持设置备注和密码。
    SharpZipLib的官方地址是:http://icsharpcode.github.io/SharpZipLib/,实际使用可以通过NuGet获取,在NuGetd地址是: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       try101       {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             else121             {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                   do132                   {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完全兼容。如果您在代码中发现问题或有可以优化完善的地方,欢迎指出,谢谢!
程序源代码下载:http://files.cnblogs.com/files/conexpress/SharpZipTest.zip
 
参考资料:
http://www.cnblogs.com/kissdodog/p/3525295.html
http://www.cnblogs.com/xuanye/archive/2011/10/19/2217211.html