C#执行zip文件压缩的几种方法及我遇到的坑总结

工作项目中需要用到zip压缩解压缩文件,一开始看上了Ionic.Zip.dll这个类库,操作方便,写法简单

对应有个ziphelper类

 1 using Ionic.Zip;
 2 
 3     public static class ZipHelper
 4     {
 5 
 6         public static void UnZip(string zipPath, string outPath)
 7         {
 8             try
 9             {
10                 using (ZipFile zip = ZipFile.Read(zipPath))
11                 {
12                     foreach (ZipEntry entry in zip)
13                     {
14                         entry.Extract(outPath, ExtractExistingFileAction.OverwriteSilently);
15                     }
16                 }
17             }
18             catch(Exception ex)
19             {
20                 File.WriteAllText(System.Web.HttpContext.Current.Server.MapPath("/1.txt"),ex.Message + "
" + ex.StackTrace);
21             }
22         }
23         /// <summary>
24         /// 递归子目录时调用
25         /// ZipHelper.Zip(files, path + model.CName + "/" + siteid + ".zip", path + model.CName + "/");
26        /// ZipHelper.ZipDir( path + model.CName + "/" + siteid + ".zip", path + model.CName + "/", path + model.CName + "/");
27         /// </summary>
28         /// <param name="savefileName">要保存的文件名</param>
29         /// <param name="childPath">要遍历的目录</param>
30         /// <param name="startPath">压缩包起始目录结尾必须反斜杠</param>
31 
32         public static void ZipDir(string savefileName, string childPath, string startPath)
33         {
34             DirectoryInfo di = new DirectoryInfo(childPath);
35             if (di.GetDirectories().Length > 0) //有子目录
36             {
37                 foreach (DirectoryInfo dirs in di.GetDirectories())
38                 {
39                     string[] n = Directory.GetFiles(dirs.FullName, "*");
40                     Zip(n, savefileName, startPath);
41                     ZipDir(savefileName, dirs.FullName, startPath);
42                 }
43             }
44         }
45         /// <summary>
46         /// 压缩zip
47         /// </summary>
48         /// <param name="fileToZips">文件路径集合</param>
49         /// <param name="zipedFile">想要压成zip的文件名</param>
50         /// <param name="fileDirStart">文件夹起始目录结尾必须反斜杠</param>
51         public static void Zip(string[] fileToZips, string zipedFile,string fileDirStart)
52         {
53             using (ZipFile zip = new ZipFile(zipedFile, Encoding.UTF8))
54             {
55                 foreach (string fileToZip in fileToZips)
56                 { 
57                     string fileName = fileToZip.Substring(fileToZip.LastIndexOf("\", StringComparison.Ordinal) + 1);
58                     zip.AddFile(fileToZip, fileToZip.Replace(fileDirStart, "").Replace(fileName, ""));
59                     //zip.AddFile(fileToZip, fileToZip.Replace(fileDirStart, "").Replace(fileName, ""));
60                     //using (var fs = new FileStream(fileToZip, FileMode.Open, FileAccess.ReadWrite))
61                     //{
62                     //    var buffer = new byte[fs.Length];
63                     //    fs.Read(buffer, 0, buffer.Length);
64                     //    string fileName = fileToZip.Substring(fileToZip.LastIndexOf("\", StringComparison.Ordinal) + 1);
65                     //    zip.AddEntry(fileName, buffer);
66                     //}
67                 }
68                 zip.Save();
69             }
70         }
71 
72         public static void ZipOneFile(string from, string zipedFile, string to)
73         {
74             using (ZipFile zip = new ZipFile(zipedFile, Encoding.UTF8))
75             {
76                 zip.AddFile(from, to);
77                 zip.Save();
78             }
79         }
80 
81     }

使用方法:

    string path = Request.MapPath("/");
    string[] files = Directory.GetFiles(path, "*");
    ZipHelper.Zip(files, path + "1.zip", path);//压缩path下的所有文件
    ZipHelper.ZipDir(path + "1.zip", path, path);//递归压缩path下的文件夹里的文件
    ZipHelper.UnZip(Server.MapPath("/") + "lgs.zip", Server.MapPath("/"));//解压缩

正常情况下这个使用是不会有问题的,我一直在用,不过我遇到了一个变态问题,服务器端为了安全需求,禁用了File.Move方法,然后这个类库解压缩时采用了重命名方案,然后很尴尬的执行失败,困扰了我大半年时间,一直不知道原因,不过因为这个bug时隐时现,在 个别服务器上出现,所以一直没有解决,总算最近发现问题了。

于是我想干脆不用zip压缩了,直接调用服务器上的WinRar,这个问题显而易见,服务器如果没有安装,或者不给权限同样无法使用,我就遇到了,不过给个操作方法代码

  1 public class WinRarHelper
  2 {
  3     public WinRarHelper()
  4     {
  5 
  6     }
  7 
  8     static WinRarHelper()
  9     {
 10         //判断是否安装了WinRar.exe
 11         RegistryKey key = Registry.LocalMachine.OpenSubKey(@"SOFTWAREMicrosoftWindowsCurrentVersionApp PathsWinRAR.exe");
 12         _existSetupWinRar = !string.IsNullOrEmpty(key.GetValue(string.Empty).ToString());
 13 
 14         //获取WinRar.exe路径
 15         _winRarPath = key.GetValue(string.Empty).ToString();
 16     }
 17 
 18     static bool _existSetupWinRar;
 19     /// <summary>
 20     /// 获取是否安装了WinRar的标识
 21     /// </summary>
 22     public static bool ExistSetupWinRar
 23     {
 24         get { return _existSetupWinRar; }
 25     }
 26 
 27     static string _winRarPath;
 28     /// <summary>
 29     /// 获取WinRar.exe路径
 30     /// </summary>
 31     public static string WinRarPath
 32     {
 33         get { return _winRarPath; }
 34     }
 35 
 36     #region 压缩到.rar,这个方法针对目录压缩
 37     /// <summary>
 38     /// 压缩到.rar,这个方法针对目录压缩
 39     /// </summary>
 40     /// <param name="intputPath">输入目录</param>
 41     /// <param name="outputPath">输出目录</param>
 42     /// <param name="outputFileName">输出文件名</param>
 43     public static void CompressRar(string intputPath, string outputPath, string outputFileName)
 44     {
 45         //rar 执行时的命令、参数
 46         string rarCmd;
 47         //启动进程的参数
 48         ProcessStartInfo processStartInfo = new ProcessStartInfo();
 49         //进程对象
 50         Process process = new Process();
 51         try
 52         {
 53             if (!ExistSetupWinRar)
 54             {
 55                 throw new ArgumentException("请确认服务器上已安装WinRar应用!");
 56             }
 57             //判断输入目录是否存在
 58             if (!Directory.Exists(intputPath))
 59             {
 60                 throw new ArgumentException("指定的要压缩目录不存在!");
 61             }
 62             //命令参数  uxinxin修正参数压缩文件到当前目录,而不是从盘符开始
 63             rarCmd = " a " + outputFileName + " " + "./" + " -r";
 64             //rarCmd = " a " + outputFileName + " " + outputPath + " -r";
 65             //创建启动进程的参数
 66             //指定启动文件名
 67             processStartInfo.FileName = WinRarPath;
 68             //指定启动该文件时的命令、参数
 69             processStartInfo.Arguments = rarCmd;
 70             //指定启动窗口模式:隐藏
 71             processStartInfo.WindowStyle = ProcessWindowStyle.Hidden;
 72             //指定压缩后到达路径
 73             processStartInfo.WorkingDirectory = outputPath;
 74             //创建进程对象
 75             
 76             //指定进程对象启动信息对象
 77             process.StartInfo = processStartInfo;
 78             //启动进程
 79             process.Start();
 80             //指定进程自行退行为止
 81             process.WaitForExit();
 82             //Uxinxin增加的清理关闭,不知道是否有效
 83             process.Close();
 84             process.Dispose();
 85         }
 86         catch (Exception ex)
 87         {
 88             throw ex;
 89         }
 90         finally
 91         {
 92             process.Close();
 93             process.Dispose();
 94 
 95         }
 96     }
 97     #endregion
 98 
 99     #region 解压.rar
100     /// <summary>
101     /// 解压.rar
102     /// </summary>
103     /// <param name="inputRarFileName">输入.rar</param>
104     /// <param name="outputPath">输出目录</param>
105     public static void UnCompressRar(string inputRarFileName, string outputPath)
106     {
107         //rar 执行时的命令、参数
108         string rarCmd;
109         //启动进程的参数
110         ProcessStartInfo processStartInfo = new ProcessStartInfo();
111         //进程对象
112         Process process = new Process();
113         try
114         {
115             if (!ExistSetupWinRar)
116             {
117                 throw new ArgumentException("请确认服务器上已安装WinRar应用!");
118             }
119             //如果压缩到目标路径不存在
120             if (!Directory.Exists(outputPath))
121             {
122                 //创建压缩到目标路径
123                 Directory.CreateDirectory(outputPath);
124             }
125             rarCmd = "x " + inputRarFileName + " " + outputPath + " -y";
126 
127 
128             processStartInfo.FileName = WinRarPath;
129             processStartInfo.Arguments = rarCmd;
130             processStartInfo.WindowStyle = ProcessWindowStyle.Hidden;
131             processStartInfo.WorkingDirectory = outputPath;
132 
133 
134             process.StartInfo = processStartInfo;
135             process.Start();
136             process.WaitForExit();
137             process.Close();
138             process.Dispose();
139         }
140         catch (Exception ex)
141         {
142             throw ex;
143         }
144         finally
145         {
146             process.Close();
147             process.Dispose();
148         }
149     }
150     #endregion
151 
152     #region 将传入的文件列表压缩到指定的目录下
153     /// <summary>
154     /// 将传入的文件列表压缩到指定的目录下
155     /// </summary>
156     /// <param name="sourceFilesPaths">要压缩的文件路径列表</param>
157     /// <param name="compressFileSavePath">压缩文件存放路径</param>
158     /// <param name="compressFileName">压缩文件名(全名)</param>
159     public static void CompressFilesToRar(List<string> sourceFilesPaths, string compressFileSavePath, string compressFileName)
160     {
161         //rar 执行时的命令、参数
162         string rarCmd;
163         //启动进程的参数
164         ProcessStartInfo processStartInfo = new ProcessStartInfo();
165         //创建进程对象
166         //进程对象
167         Process process = new Process();
168         try
169         {
170             if (!ExistSetupWinRar)
171             {
172                 throw new ArgumentException("Not setuping the winRar, you can Compress.make sure setuped winRar.");
173             }
174             //判断输入文件列表是否为空
175             if (sourceFilesPaths == null || sourceFilesPaths.Count < 1)
176             {
177                 throw new ArgumentException("CompressRar'arge : sourceFilesPaths cannot be null.");
178             }
179             rarCmd = " a -ep1 -ap " + compressFileName;
180                 //-ep1 -ap表示压缩时不保留原有文件的路径,都压缩到压缩包中即可,调用winrar命令内容可以参考我转载的另一篇文章:教你如何在DOS(cmd)下使用WinRAR压缩文件
181             foreach (object filePath in sourceFilesPaths)
182             {
183                 rarCmd += " " + filePath.ToString(); //每个文件路径要与其他的文件用空格隔开
184             }
185             //rarCmd += " -r";
186             //创建启动进程的参数
187 
188             //指定启动文件名
189             processStartInfo.FileName = WinRarPath;
190             //指定启动该文件时的命令、参数
191             processStartInfo.Arguments = rarCmd;
192             //指定启动窗口模式:隐藏
193             processStartInfo.WindowStyle = ProcessWindowStyle.Hidden;
194             //指定压缩后到达路径
195             processStartInfo.WorkingDirectory = compressFileSavePath;
196 
197             //指定进程对象启动信息对象
198             process.StartInfo = processStartInfo;
199             //启动进程
200             process.Start();
201             //指定进程自行退行为止
202             process.WaitForExit();
203             process.Close();
204             process.Dispose();
205         }
206         catch (Exception ex)
207         {
208             throw ex;
209         }
210         finally
211         {
212             process.Close();
213             process.Dispose();
214         }
215     }
216     #endregion
217 }

调用方法:

if (WinRarHelper.ExistSetupWinRar)
        {
            try
            {
                WinRarHelper.CompressRar(Server.MapPath("/"), Server.MapPath("/"), "1.zip");
                Response.Write("压缩完成!" + DateTime.Now);
            }
            catch (Win32Exception e1)
            {
                Response.Write(e1.Message + "<br>" + "服务器端禁止是我们网站使用WinRar应用执行!<br>");
            }
            catch (Exception e1)
            {
                Response.Write(e1.Message + "<br>" + e1.StackTrace);
            }

        if (WinRarHelper.ExistSetupWinRar)
        {
            try
            {
                WinRarHelper.UnCompressRar(Server.MapPath("/") + "lgs.zip", Server.MapPath("/"));
                Response.Write("解压缩完成!" + DateTime.Now);
            }
            catch (Win32Exception e1)
            {
                Response.Write(e1.Message + "<br>" + "服务器端禁止是我们网站使用WinRar应用执行!<br>");

            }
            catch (Exception e1)
            {
                Response.Write(e1.Message);
            }
        }

最后我找到了一个解压的时候不用重命名方法的,还好服务器对解压没限制

ICSharpCode.SharpZipLib.dll  用到这个文件

参考来自http://www.cnblogs.com/yuangang/p/5581391.html

具体我也不写了,就看参考网站吧,我也没改代码,不错,记录一下,花了我整整一天折腾这玩意儿!

原文地址:https://www.cnblogs.com/uxinxin/p/6268195.html