ASP.NET 提供多種方式將檔案推送給瀏覽器並觸發「另存新檔」對話框。本文比較 Response.TransmitFile、Response.BinaryWrite、Response.OutputStream 三種核心方法,並說明 Content-Disposition 標頭、MIME 類型設定與常見 GDI+ 錯誤解決方案。
| 方法 | 適用情境 | 記憶體影響 | 大檔案支援 |
|---|---|---|---|
| Response.TransmitFile(path) | 實體檔案直接輸出 | 極低 (核心傳輸) | 優 (GB 級無壓力) |
| Response.BinaryWrite(byte[]) | 記憶體位元組陣列 (如動態產生圖片) | 高 (全量載入記憶體) | 差 (受限於記憶體) |
| Response.OutputStream.Write() | 串流式寫入 (如壓縮串流、加密串流) | 可控 (分塊寫入) | 良 (配合 BufferedStream) |
Response.ContentType = "image/jpeg";
Response.AppendHeader("Content-Disposition", "attachment; filename=SailBig.jpg");
Response.TransmitFile(Server.MapPath("~/images/sailbig.jpg"));
Response.End();
Bitmap bmp = GenerateCornerImage(...); // 動態產生圖片
Response.ContentType = "image/jpeg";
Response.AppendHeader("Content-Disposition", "attachment; filename=Corner.jpg");
bmp.Save(Response.OutputStream, ImageFormat.Jpeg); // 直接存入輸出串流
bmp.Dispose();
Response.End();
attachment:強制下載對話框。inline:瀏覽器嘗試直接顯示 (如圖片、PDF)。filename="...":建議檔名,支援 RFC 5987 編碼 (filename*=UTF-8''%E6%AA%94%E6%A1%88.jpg) 解決中文檔名亂碼。application/pdf、application/zip、image/png、text/csv、application/vnd.ms-excel現象:從資源檔或資料庫 BLOB 讀取 Bitmap 後 Save(Response.OutputStream) 拋出 "A generic error occurred in GDI+"。
原因:資源檔/資料庫回傳的 Bitmap 內部串流不可重複寫入或鎖定。
解決:建立新 Bitmap 複本再儲存。
Bitmap src = (Bitmap)GetGlobalResourceObject("Resource", "_BitMap");
using (Bitmap clone = new Bitmap(src)) // 複本可自由存取
{
Response.ContentType = "image/jpeg";
clone.Save(Response.OutputStream, ImageFormat.Jpeg);
}
src.Dispose();
Response.End();
Response.TransmitFile (IIS 7.5+ 支援核心快取、斷點續傳)。Response.BufferOutput = false 避免伺服器端緩衝整個檔案。ETag/Last-Modified 支援瀏覽器快取與續傳。../),使用 Path.GetFullPath 比對允許根目錄。