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

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

http://msdn.microsoft.com/en-gb/library/aa686114(zh-cn).aspx#EHAA得来全不费功夫啊),贴出来找到的代码,大家共同学习。

 

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

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

 需要添加对SharpZipLib的引用:

using ICSharpCode.SharpZipLib.Zip;
 
posted @ 2014-08-07 14:24  程序新青年  阅读(376)  评论(0编辑  收藏  举报
============================================================================== 青春匆匆,很多人都有自己的座右铭,鞭策自己前进,当没看到座右铭的时候又忘了自己要干什么,就这样天天立志,志天天立,最终还是那个初出茅庐的小菜鸟。从现在开始,慢慢去改掉懒惰的习惯。慢慢去加强学习,直到慢慢成功。==============================================================================