透過 `Response.OutputStream` 將檔案二進位內容直接推送給瀏覽器,支援斷點續傳、大檔案、自訂檔名與 MIME 類型。
///
/// 將檔案推送至客戶端瀏覽器下載
/// 注意:不可置於 AJAX UpdatePanel 內部;觸發按鈕需在 UpdatePanel 外部
///
protected void DownloadFile(string fullFilePath)
{
// 1. 取得檔名
string fileName = fullFilePath.Substring(fullFilePath.LastIndexOf('\\') + 1);
// 2. 讀取檔案到位元組陣列
byte[] buffer;
using (FileStream fs = new FileStream(fullFilePath, FileMode.Open, FileAccess.Read))
{
int fileSize = (int)fs.Length;
buffer = new byte[fileSize];
fs.Read(buffer, 0, fileSize);
}
// 3. 設定回應標頭
Response.Clear();
Response.Buffer = true;
Response.BufferOutput = true;
Response.ContentType = "application/x-download"; // 強制下載
Response.AddHeader("Content-Disposition", "attachment; filename=" + HttpUtility.UrlEncode(fileName));
Response.CacheControl = "public";
// 4. 輸出並結束
Response.OutputStream.Write(buffer, 0, buffer.Length);
Response.End(); // 或 Response.Flush() + HttpContext.Current.ApplicationInstance.CompleteRequest()
}
| 設定 | 用途 |
|---|---|
| ContentType | `application/octet-stream` 或具體 MIME (如 `application/pdf`),`application/x-download` 強制下載對話框 |
| Content-Disposition | `attachment` 強制下載;`inline` 瀏覽器嘗試直接顯示 (PDF/圖片)。檔名需 `UrlEncode` 避免中文亂碼 |
| Buffer/BufferOutput | 啟用緩衝避免大檔案佔用記憶體,配合 `Flush` 分批輸出更佳 |
| Response.End() | 立即終止處理管線,慎用於 UpdatePanel/非同步請求 |
const int BufferSize = 65536; // 64KB
using (FileStream fs = new FileStream(fullFilePath, FileMode.Open, FileAccess.Read))
{
byte[] buffer = new byte[BufferSize];
int bytesRead;
while ((bytesRead = fs.Read(buffer, 0, BufferSize)) > 0)
{
if (!Response.IsClientConnected) break; // 用戶中斷下載
Response.OutputStream.Write(buffer, 0, bytesRead);
Response.Flush();
}
}
Response.End();
需解析 `Request.Headers["Range"]`,回應 `206 Partial Content`、`Content-Range`、`Accept-Ranges: bytes`。建議使用成熟函式庫 (如 `FileResult`、`PhysicalFileResult` ASP.NET Core 內建)。
注意: ASP.NET Core 請使用 `return PhysicalFile(path, "application/octet-stream", fileName)` 或 `FileStreamResult`,內建支援 Range 請求與非同步串流。