在ASP.NET中实现压缩多个文件为.zip文件,实现批量下载功能 (转载并优化处理篇)

转自:http://blog.csdn.net/yanlele424/article/details/6895986

这段时间一直在做一个网站,其中遇到了一个问题,就是在服务器端压缩多个服务器端的文件,然后在供客户下载。说白了就是用户上传了多个文件,然后别的用户可以点击批量下载这些文件。我要做的就是实现把这些文件压缩之后供用户下载。         我首先想到的是.Net提供的GZipStream类,翻了一下书才发现GZipStream没有提供加压多个文件的方法,需要自己定义,这样解压也只有使用自己的程序才可以。这不是我想要的效果,放弃这个方案。由于之前没有接触过这方面的技术,只有在网上找,结果找到多种解决的方案,大部分的方法都要使用外部的类库。这里列出来一个最常用的,以备以后查找方便: SharpZipLib (参见文章http://www.cnblogs.com/tuyile006/archive/2008/04/25/1170894.html

使用ICSharpCode.SharpZipLib.dll;     下载地址    http://www.icsharpcode.net/OpenSource/SharpZipLib/Download.aspx

下面是对#ZipLib进行.net下的解压缩的方法的介绍。                 1.BZip2                加入ICSharpCode.SharpZipLib.dll的引用,在#Develop的安装目录下的\SharpDevelop\bin目录下。然后在程序中使用using语句把BZip2          类库包含进来。        压缩:使用BZip2的静态方法Compress。                它的第一个参数是所要压缩的文件所代表的输入流,可以使用System.IO.File的静态方法OpenRead。               第二个参数是要建立的压缩文件所代表的输出流,可以使用System.IO.File的静态方法Create创建,压缩文件名是所要压缩文件的文件名          加上压缩后缀.bz(同样你也可以取其他的文件名)。                第三个参数是要压缩的块大小(一般为2048的整数)。             解压:使用BZip2的静态方法Decompress。                它的第一个参数是所要解压的压缩文件所代表的输入流,可以使用System.IO.File的静态方法OpenRead。               第二个参数是要建立的解压文件所代表的输出流,可以使用System.IO.File的静态方法Create创建,因为解压文件的文件名是去掉了压缩          文件扩展名的压缩文件名(你也可以做成解压文件与压缩文件不同名的)。        编译你的程序,然后在命令行方式下输入bzip2   文件名(假设建立的C#文件是bzip2,就可以生成压缩文件;输入bzip2   -d   文件名,就会解压          出文件来(-d是用来表示解压,你也可以使用其他的符号)。        呵呵,原来做压缩可以这么简单的,压缩效果也可以啊。

  1. using   System;
  2. using   System.IO;
  3. using   ICSharpCode.SharpZipLib.BZip2;
  4. class   MainClass
  5. {
  6. public   static   void   Main(string[]   args)
  7. {
  8. if   (args[0]   ==   "-d")   {   //   解压
  9. BZip2.Decompress(File.OpenRead(args[1]),   File.Create(Path.GetFileNameWithoutExtension(args[1])));
  10. }   else   {   //压缩
  11. BZip2.Compress(File.OpenRead(args[0]),   File.Create(args[0]   +   ".bz"),   4096);
  12. }
  13. }
  14. }

2.GZip                加入ICSharpCode.SharpZipLib.dll的引用,在#Develop的安装目录下的\SharpDevelop\bin目录下。然后在程序中使用using语句把GZip类          库包含进来。                由于GZip没有BZip2的简单解压缩方法,因此只能使用流方法来进行解压缩。具体的方法见程序的说明。             编译程序,然后在命令行方式下输入GZip   文件名(假设建立的C#文件是GZip,就可以生成压缩文件;输入GZip   -d   文件名,就会解压出文          件来(-d是用来表示解压,你也可以使用其他的符号)。

  1. using   System;
  2. using   System.IO;
  3. using   ICSharpCode.SharpZipLib.GZip;
  4. class   MainClass
  5. {
  6. public   static   void   Main(string[]   args)
  7. {
  8. if   (args[0]   ==   "-d")   {   //   解压
  9. Stream   s   =   new   GZipInputStream(File.OpenRead(args[1]));
  10. //生成一个GZipInputStream流,用来打开压缩文件。
  11. //因为GZipInputStream由Stream派生,所以它可以赋给Stream。
  12. //它的构造函数的参数是一个表示要解压的压缩文件所代表的文件流
  13. FileStream   fs   =   File.Create(Path.GetFileNameWithoutExtension(args[1]));
  14. //生成一个文件流,它用来生成解压文件
  15. //可以使用System.IO.File的静态函数Create来生成文件流
  16. int   size   =   2048;//指定压缩块的大小,一般为2048的倍数
  17. byte[]   writeData   =   new   byte[size];//指定缓冲区的大小
  18. while   (true)   {
  19. size   =   s.Read(writeData,   0,   size);//读入一个压缩块
  20. if   (size   >   0)   {
  21. fs.Write(writeData,   0,   size);//写入解压文件代表的文件流
  22. }   else   {
  23. break;//若读到压缩文件尾,则结束
  24. }
  25. }
  26. s.Close();
  27. }   else   {   //   压缩
  28. Stream   s   =   new   GZipOutputStream(File.Create(args[0]   +   ".gz"));
  29. //生成一个GZipOutputStream流,用来生成压缩文件。
  30. //因为GZipOutputStream由Stream派生,所以它可以赋给Stream。
  31. FileStream   fs   =   File.OpenRead(args[0]);
  32. /生成一个文件流,它用来打开要压缩的文件
  33. //可以使用System.IO.File的静态函数OpenRead来生成文件流
  34. byte[]   writeData   =   new   byte[fs.Length];
  35. //指定缓冲区的大小
  36. fs.Read(writeData,   0,   (int)fs.Length);
  37. //读入文件
  38. s.Write(writeData,   0,   writeData.Length);
  39. //写入压缩文件
  40. s.Close();
  41. //关闭文件
  42. }
  43. }
  44. }

使用这个类库固然好,但是也有些缺陷,它只能压缩文件夹第一级子目录中的“文件”(不包括文件夹和子目录)的情况,这也不能满足我的要求,我想要的是可以压缩任意路径的多个文件。       没办法,只好再想别的办法。郁闷了很久之后在别人的一篇文章中终于找到了灵感,别人的一篇文章是写在java中实现压缩zip文件,我看了后发现在java中实现压缩为zip文件很容易。灵机一动我想到了.net中的J#,J#中应该有java中的这样类,如果有的话,那么我在我的C#程序中就可以引用了(利用.net特有的语言互操作性)。于是我就上网搜这方面的内容,终于在MSDN中找到了这样的例子

http://msdn.microsoft.com/en-gb/library/aa686114(zh-cn).aspx#EHAA得来全不费功夫啊在ASP.NET中实现压缩多个文件为.zip文件,实现批量下载功能 (转载并优化处理篇)),贴出来找到的代码,大家共同学习。

  1. using System;
  2. using System.Collections;
  3. using java.util;
  4. using java.util.zip;
  5. namespace CsZip
  6. {
  7. public delegate Enumeration EnumerationMethod();
  8. /// <summary>
  9. /// Wraps java enumerators
  10. /// </summary>
  11. public class EnumerationAdapter : IEnumerable
  12. {
  13. private class EnumerationWrapper : IEnumerator
  14. {
  15. private EnumerationMethod m_Method;
  16. private Enumeration m_Wrapped;
  17. private object m_Current;
  18. public EnumerationWrapper(EnumerationMethod method)
  19. {
  20. m_Method = method;
  21. }
  22. // IEnumerator
  23. public object Current
  24. {
  25. get { return m_Current; }
  26. }
  27. public void Reset()
  28. {
  29. m_Wrapped = m_Method();
  30. if (m_Wrapped == null)
  31. throw new InvalidOperationException();
  32. }
  33. public bool MoveNext()
  34. {
  35. if (m_Wrapped == null)
  36. Reset();
  37. bool Result = m_Wrapped.hasMoreElements();
  38. if (Result)
  39. m_Current = m_Wrapped.nextElement();
  40. return Result;
  41. }
  42. }
  43. private EnumerationMethod m_Method;
  44. public EnumerationAdapter(EnumerationMethod method)
  45. {
  46. if (method == null)
  47. throw new ArgumentException();
  48. m_Method = method;
  49. }
  50. // IEnumerable
  51. public IEnumerator GetEnumerator()
  52. {
  53. return new EnumerationWrapper(m_Method);
  54. }
  55. }
  56. public delegate bool FilterEntryMethod(ZipEntry e);
  57. /// <summary>
  58. /// Zip stream utils
  59. /// </summary>
  60. public class ZipUtility
  61. {
  62. public static void CopyStream(java.io.InputStream from, java.io.OutputStream to)
  63. {
  64. sbyte[] buffer = new sbyte[8192];
  65. int got;
  66. while ((got = from.read(buffer, 0, buffer.Length)) > 0)
  67. to.write(buffer, 0, got);
  68. }
  69. public static void ExtractZipFile(ZipFile file, string path, FilterEntryMethod filter)
  70. {
  71. foreach (ZipEntry entry in new EnumerationAdapter(new EnumerationMethod(file.entries)))
  72. {
  73. if (!entry.isDirectory())
  74. {
  75. if ((filter == null || filter(entry)))
  76. {
  77. java.io.InputStream s = file.getInputStream(entry);
  78. try
  79. {
  80. string fname = System.IO.Path.GetFileName(entry.getName());
  81. string newpath = System.IO.Path.Combine(path, System.IO.Path.GetDirectoryName(entry.getName()));
  82. System.IO.Directory.CreateDirectory(newpath);
  83. java.io.FileOutputStream dest = new java.io.FileOutputStream(System.IO.Path.Combine(newpath, fname));
  84. try
  85. {
  86. CopyStream(s, dest);
  87. }
  88. finally
  89. {
  90. dest.close();
  91. }
  92. }
  93. finally
  94. {
  95. s.close();
  96. }
  97. }
  98. }
  99. }
  100. }
  101. /// <summary>
  102. /// 创建新的Zip文件
  103. /// </summary>
  104. /// <param name="fileName">Zip文件的路径</param>
  105. /// <returns>Zip文件的路径</returns>
  106. public static ZipFile CreateEmptyZipFile(string fileName)
  107. {
  108. new ZipOutputStream(new java.io.FileOutputStream(fileName)).close();
  109. return new ZipFile(fileName);
  110. }
  111. /// <summary>
  112. /// 向存在的Zip文件中添加待压缩的文件
  113. /// </summary>
  114. /// <param name="file">Zip文件</param>
  115. /// <param name="filter"></param>
  116. /// <param name="newFiles">待压缩的文件的路径</param>
  117. /// <returns></returns>
  118. public static ZipFile UpdateZipFile(ZipFile file, FilterEntryMethod filter, string[] newFiles)
  119. {
  120. string prev = file.getName();
  121. string tmp = System.IO.Path.GetTempFileName();
  122. ZipOutputStream to = new ZipOutputStream(new java.io.FileOutputStream(tmp));
  123. try
  124. {
  125. CopyEntries(file, to, filter);
  126. // add entries here
  127. if (newFiles != null)
  128. {
  129. foreach (string f in newFiles)
  130. {
  131. ZipEntry z = new ZipEntry(f.Remove(0, System.IO.Path.GetPathRoot(f).Length));
  132. z.setMethod(ZipEntry.DEFLATED);
  133. to.putNextEntry(z);
  134. try
  135. {
  136. java.io.FileInputStream s = new java.io.FileInputStream(f);
  137. try
  138. {
  139. CopyStream(s, to);
  140. }
  141. finally
  142. {
  143. s.close();
  144. }
  145. }
  146. finally
  147. {
  148. to.closeEntry();
  149. }
  150. }
  151. }
  152. }
  153. finally
  154. {
  155. to.close();
  156. }
  157. file.close();
  158. // now replace the old file with the new one
  159. System.IO.File.Copy(tmp, prev, true);
  160. System.IO.File.Delete(tmp);
  161. return new ZipFile(prev);
  162. }
  163. public static void CopyEntries(ZipFile from, ZipOutputStream to)
  164. {
  165. CopyEntries(from, to, null);
  166. }
  167. public static void CopyEntries(ZipFile from, ZipOutputStream to, FilterEntryMethod filter)
  168. {
  169. foreach (ZipEntry entry in new EnumerationAdapter(new EnumerationMethod(from.entries)))
  170. {
  171. if (filter == null || filter(entry))
  172. {
  173. java.io.InputStream s = from.getInputStream(entry);
  174. try
  175. {
  176. to.putNextEntry(entry);
  177. try
  178. {
  179. CopyStream(s, to);
  180. }
  181. finally
  182. {
  183. to.closeEntry();
  184. }
  185. }
  186. finally
  187. {
  188. s.close();
  189. }
  190. }
  191. }
  192. }
  193. }
  194. }

使用国外开源加压解压库ICSharpCode.SharpZipLib实现加压,该库的官方网站为

http://www.icsharpcode.net/OpenSource/SharpZipLib/Download.aspx

使用体验:可以照着例子实现简单的加压解压,可以加压一个文件夹中的所有文件,但没有提供加压子文件夹的说明。 目前网上的一些代码有的无法加压空文件夹,有的加压了用rar解不开,这是一点需要改进的。 但如果只需要加压文件夹第一级子目录中的“文件”(不包括文件夹和子目录)的情况,使用这个库是很方便的。而且是正常zip格式。 比.Net提供的GZipStream类强在它可以按照标准zip格式加压多个文件,而GZipStream没有提供加压多个文件的方法,需要自己定义, 这样解压也只有使用自己的程序才可以,通用性方面不如SharpZipLib。

  1. #region 加压解压方法
  2. /// <summary>
  3. /// 功能:压缩文件(暂时只压缩文件夹下一级目录中的文件,文件夹及其子级被忽略)
  4. /// </summary>
  5. /// <param name="dirPath">被压缩的文件夹夹路径</param>
  6. /// <param name="zipFilePath">生成压缩文件的路径,为空则默认与被压缩文件夹同一级目录,名称为:文件夹名+.zip</param>
  7. /// <param name="err">出错信息</param>
  8. /// <returns>是否压缩成功</returns>
  9. public bool ZipFile(string dirPath, string zipFilePath, out string err)
  10. {
  11. err = "";
  12. if (dirPath == string.Empty)
  13. {
  14. err = "要压缩的文件夹不能为空!";
  15. return false;
  16. }
  17. if (!Directory.Exists(dirPath))
  18. {
  19. err = "要压缩的文件夹不存在!";
  20. return false;
  21. }
  22. //压缩文件名为空时使用文件夹名+.zip
  23. if (zipFilePath == string.Empty)
  24. {
  25. if (dirPath.EndsWith("\\"))
  26. {
  27. dirPath = dirPath.Substring(0, dirPath.Length - 1);
  28. }
  29. zipFilePath = dirPath + ".zip";
  30. }
  31. try
  32. {
  33. string[] filenames = Directory.GetFiles(dirPath);
  34. using (ZipOutputStream s = new ZipOutputStream(File.Create(zipFilePath)))
  35. {
  36. s.SetLevel(9);
  37. byte[] buffer = new byte[4096];
  38. foreach (string file in filenames)
  39. {
  40. ZipEntry entry = new ZipEntry(Path.GetFileName(file));
  41. entry.DateTime = DateTime.Now;
  42. s.PutNextEntry(entry);
  43. using (FileStream fs = File.OpenRead(file))
  44. {
  45. int sourceBytes;
  46. do
  47. {
  48. sourceBytes = fs.Read(buffer, 0, buffer.Length);
  49. s.Write(buffer, 0, sourceBytes);
  50. } while (sourceBytes > 0);
  51. }
  52. }
  53. s.Finish();
  54. s.Close();
  55. }
  56. }
  57. catch (Exception ex)
  58. {
  59. err = ex.Message;
  60. return false;
  61. }
  62. return true;
  63. }
  64. /// <summary>
  65. /// 功能:解压zip格式的文件。
  66. /// </summary>
  67. /// <param name="zipFilePath">压缩文件路径</param>
  68. /// <param name="unZipDir">解压文件存放路径,为空时默认与压缩文件同一级目录下,跟压缩文件同名的文件夹</param>
  69. /// <param name="err">出错信息</param>
  70. /// <returns>解压是否成功</returns>
  71. public bool UnZipFile(string zipFilePath, string unZipDir, out string err)
  72. {
  73. err = "";
  74. if (zipFilePath == string.Empty)
  75. {
  76. err = "压缩文件不能为空!";
  77. return false;
  78. }
  79. if (!File.Exists(zipFilePath))
  80. {
  81. err = "压缩文件不存在!";
  82. return false;
  83. }
  84. //解压文件夹为空时默认与压缩文件同一级目录下,跟压缩文件同名的文件夹
  85. if (unZipDir == string.Empty)
  86. unZipDir = zipFilePath.Replace(Path.GetFileName(zipFilePath), Path.GetFileNameWithoutExtension(zipFilePath));
  87. if (!unZipDir.EndsWith("\\"))
  88. unZipDir += "\\";
  89. if (!Directory.Exists(unZipDir))
  90. Directory.CreateDirectory(unZipDir);
  91. try
  92. {
  93. using (ZipInputStream s = new ZipInputStream(File.OpenRead(zipFilePath)))
  94. {
  95. ZipEntry theEntry;
  96. while ((theEntry = s.GetNextEntry()) != null)
  97. {
  98. string directoryName = Path.GetDirectoryName(theEntry.Name);
  99. string fileName = Path.GetFileName(theEntry.Name);
  100. if (directoryName.Length > 0)
  101. {
  102. Directory.CreateDirectory(unZipDir + directoryName);
  103. }
  104. if (!directoryName.EndsWith("\\"))
  105. directoryName += "\\";
  106. if (fileName != String.Empty)
  107. {
  108. using (FileStream streamWriter = File.Create(unZipDir + theEntry.Name))
  109. {
  110. int size = 2048;
  111. byte[] data = new byte[2048];
  112. while (true)
  113. {
  114. size = s.Read(data, 0, data.Length);
  115. if (size > 0)
  116. {
  117. streamWriter.Write(data, 0, size);
  118. }
  119. else
  120. {
  121. break;
  122. }
  123. }
  124. }
  125. }
  126. }//while
  127. }
  128. }
  129. catch (Exception ex)
  130. {
  131. err = ex.Message;
  132. return false;
  133. }
  134. return true;
  135. }//解压结束
  136. #endregion

需要添加对SharpZipLib的引用:

using ICSharpCode.SharpZipLib.Zip;
 
上一篇:Postman查看上传文件过程时出现400 - Required MultipartFile parameter 'files' is not present错误


下一篇:JavaScript 获取7天之前或之后的日期