在做項目的過程中有時候會遇到“下載幾十M甚至過百M的文件”這樣的需求,這時候如果還是用老方法直接將文件一次性讀取出來然后寫入到響應流,這肯定是不行的,不說別的,光是內存的消耗就可能讓服務器垮掉。那么有沒有更好的方式呢,答案是肯定的,下面分享一種使用Response.OutputStream實現大文件下載的方式。
首先,自定義一個ActionResult,代碼如下:
/// <summary> /// 該類繼承了ActionResult,通過重寫ExecuteResult方法,進行文件的下載 /// </summary> public class FileResult : ActionResult { private readonly string _filePath;//文件路徑 private readonly string _fileName;//文件名稱 public FileResult(string filePath,string fileName) { _filePath = filePath; _fileName = fileName; } public override void ExecuteResult(ControllerContext context) { string fileName = _fileName; HttpResponseBase response = context.HttpContext.Response; if (File.Exists(_filePath)) { FileStream fs = null; byte[] fileBuffer = new byte[1024];//每次讀取1024字節大小的數據 try { using (fs = File.OpenRead(_filePath)) { long totalLength = fs.Length; response.ContentType = "application/octet-stream"; response.AddHeader("Content-Disposition", "attachment; filename=" + HttpUtility.UrlEncode(fileName)); while (totalLength > 0 && response.IsClientConnected)//持續傳輸文件 { int length = fs.Read(fileBuffer, 0, fileBuffer.Length);//每次讀取1024個字節長度的內容 fs.Flush(); response.OutputStream.Write(fileBuffer, 0, length);//寫入到響應的輸出流 response.Flush();//刷新響應 totalLength = totalLength - length; } response.Close();//文件傳輸完畢,關閉相應流 } } catch (Exception ex) { response.Write(ex.Message); } finally { if (fs != null) fs.Close();//最后記得關閉文件流 } } } }
然后在Action里面直接返回一個FileResult的實例即可
public class FileController : Controller { public ActionResult Index() { return View("~/Views/File/Index.cshtml"); } // // GET: /File/ public ActionResult Download() { string filePath = Server.MapPath("~/App_Data/ASP.NETWebAPI2框架揭秘.pdf"); string fileName = "ASP.NETWebAPI2框架揭秘.pdf"; return new FileResult(filePath, fileName); } }
這里,我用了一個47.5MB大小的pdf文件做測試,效果還是不錯的。