2012-10-16 14 views
5

我想在使用DotNetZip組件的MVC方法中創建一個zipfile。在MVC中使用memorystream和DotNetZip給「不能訪問一個封閉的流」

這裏是我的代碼:

public FileResult DownloadImagefilesAsZip() 
    { 
     using (var memoryStream = new MemoryStream()) 
     { 
      using (var zip = new ZipFile()) 
      { 
       zip.AddDirectory(Server.MapPath("/Images/")); 
       zip.Save(memoryStream); 

       return File(memoryStream, "gzip", "images.zip"); 
      } 
     } 
    } 

當我運行它,我得到一個「無法訪問已關閉的流」的錯誤,我不知道爲什麼。

回答

15

請勿將MemoryStream,一旦完成將其寫入響應FileStreamResult會照顧:

public ActionResult DownloadImagefilesAsZip() 
{ 
    var memoryStream = new MemoryStream(); 
    using (var zip = new ZipFile()) 
    { 
     zip.AddDirectory(Server.MapPath("~/Images")); 
     zip.Save(memoryStream); 
     return File(memoryStream, "application/gzip", "images.zip"); 
    } 
} 

順便說一句,我會建議你寫一個自定義操作的結果來處理這個,而不是在你的控制器動作中寫入管道代碼。不僅如此,您將獲得可重用的操作結果,但請記住,您的代碼效率極低=>您正在內存中執行ZIP操作,從而將整個〜/ images目錄內容+ zip文件加載到內存中。如果你在這個目錄中有很多用戶和很多文件,你將很快耗盡內存。

一個更有效的解決方案是直接寫入響應流:

public class ZipResult : ActionResult 
{ 
    public string Path { get; private set; } 
    public string Filename { get; private set; } 

    public ZipResult(string path, string filename) 
    { 
     Path = path; 
     Filename = filename; 
    } 

    public override void ExecuteResult(ControllerContext context) 
    { 
     if (context == null) 
     { 
      throw new ArgumentNullException("context"); 
     } 

     var response = context.HttpContext.Response; 
     response.ContentType = "application/gzip"; 
     using (var zip = new ZipFile()) 
     { 
      zip.AddDirectory(Path); 
      zip.Save(response.OutputStream); 
      var cd = new ContentDisposition 
      { 
       FileName = Filename, 
       Inline = false 
      }; 
      response.Headers.Add("Content-Disposition", cd.ToString()); 
     } 
    } 
} 

然後:

public ActionResult DownloadImagefilesAsZip() 
{ 
    return new ZipResult(Server.MapPath("~/Images"), "images.zip"); 
} 
+0

完美!非常感謝:) –

+1

我不得不在'return File(...);'之前添加'memoryStream.Seek(0,SeekOrigin.Begin);'以使其工作。 – pqvst

0

無法評論。

Darin的回答非常好!仍然收到一個內存異常,但必須添加response.BufferOutput = false;因爲這必須提高內容處置代碼。

所以,你必須:

... 
     var response = context.HttpContext.Response; 
     response.ContentType = "application/zip"; 
     response.BufferOutput = false; 

     var cd = new ContentDisposition 
     { 
      FileName = ZipFilename, 
      Inline = false 
     }; 
     response.Headers.Add("Content-Disposition", cd.ToString()); 

     using (var zip = new ZipFile()) 
     { 
... 

萬一這一點不明確:)