如何在ASP.NET中下載檔案

  這是筆者常被問到的一個問題,如何透過ASP.NET來下載檔案,這個問題可大可小,我們先從小的開始。當我們要讓使用者下載一個檔案,最簡單的方式是透過Response.Redirect指令:

  Response.Redirect("test.doc")

  您可以把上面這行指令放在Button的Click事件當中,當使用者按下按鈕之後,網頁就會被轉址到該word檔,造成下載的效果。

  但是這樣的下載有幾個問題:

  1. 無法下載不存在的檔案:例如,我們若是想把程式動態(臨時)產生的文字,當作一個檔案下載的時候(也就是該檔案其實原先並不是真的存在,而是動態產生的),就無法下載。
  2. 無法下載儲存於資料庫中的檔案:這是類似的問題,該檔案並沒有真的存在,只是被存放在資料庫中的某個位置(某筆記錄中的某個欄位)的時候,就無法下載。
  3. 無法下載不存在於Web資料夾中的檔案:檔案確實存在,但該資料夾並不是可以分享出來的Web資料夾,例如,該檔案的位置在C:\winnt,您總不會想要把該資料夾當作Web資料夾吧?這時候,由於您無法使用Redirect指向該位置,所以無法下載。
  4. 下載檔案後,原本的頁面將會消失。

  典型的狀況是,我們要讓使用者下載一個.txt文字檔,或是.csv格式的Excel檔案,但是...

  1. 這個檔案可能是透過ASP.NET程式動態產生的,而不是確實存在於Server端的檔案;
  2. 或是它雖然存在於伺服器端的某個實體位置,但我們並不想暴露這個位置(如果這個位置公開,很可能沒有權限的使用者也可以在網址列上輸入URL直接取得!!!)
  3. 或是這個位置並不在網站虛擬路徑所在的資料夾中。(例如C:\Windows\System32...)

  這時候,我們就得採用不同的方式:

Shared Function DownloadFile(ByVal WebForm As System.Web.UI.Page, ByVal FileNameWhenUserDownload As String, ByVal FileBody As String)
  WebForm.Response.ClearHeaders()
  WebForm.Response.Clear()
  WebForm.Response.Expires = 0
  WebForm.Response.Buffer = True
  WebForm.Response.AddHeader("Accept-Language", "zh-tw")
  '檔案名稱
  WebForm.Response.AddHeader("content-disposition", "attachment; filename=" & Chr(34) & System.Web.HttpUtility.UrlEncode(FileNameWhenUserDownload, System.Text.Encoding.UTF8) & Chr(34))
  WebForm.Response.ContentType = "Application/octet-stream"
  '檔案內容
  WebForm.Response.Write(FileBody)
  WebForm.Response.End()
End Function


  上面這段程式碼是下載一個動態產生的文字檔,若這個檔案已經存在於伺服器端的實體路徑,則可以透過底下的函式:


Shared Sub DownloadFile(ByVal WebForm As System.Web.UI.Page, ByVal FileNameWhenUserDownload As String, ByVal FilePath As String)
  WebForm.Response.ClearHeaders()
  WebForm.Response.Clear()
  WebForm.Response.Expires = 0
  WebForm.Response.Buffer = True
  WebForm.Response.AddHeader("Accept-Language", "zh-tw")
  '檔案名稱
  WebForm.Response.AddHeader("content-disposition", "attachment; filename=" & Chr(34) & System.Web.HttpUtility.UrlEncode(FileNameWhenUserDownload, System.Text.Encoding.UTF8) & Chr(34))
  WebForm.Response.ContentType = "Application/octet-stream"
  '檔案內容
  WebForm.Response.Write(System.IO.File.ReadAllBytes(FilePath))
  WebForm.Response.End()
End Sub

上面這兩個下載檔案的的函式,應可解決大多數開發人員在ASP.NET當中的檔案下載問題。

留言

Ryan寫道…
因為常使用Ajax,想請問一下,
上述資料流下載的方式,要如何應用在Ajax中呢?
匿名表示…
非常不錯的文章喔
最近公司要用到,就找到那麼好的文章
真是非常感謝
匿名表示…
董老師, 這個...不太好吧
Alex 寶哥寫道…
請問我是下載文字檔,但是發現都會被寫入
html的標頭之類碼到文字檔內,這會造成使用者的不便以及錯誤.
請問是否有方法解決呢?
我的code參照你的以後,發現也是相差無幾,
但我就是試不出來只有原文字檔內容,
可麻煩版大幫忙一下,謝謝!!
匿名表示…
謝謝您的分享
匿名表示…
建議將 UrlEncode 改成 UrlPathEncode
原因是 file name 中有空白才不會出現 "+" 號

建議將 Write(System.IO.File.ReadAllBytes(FilePath))改成
BinaryWrite(System.IO.File.ReadAllBytes(FilePath))
原因是下載的檔案內容才不會僅出現 System.Byte[] 而不是檔案真下的內容
匿名表示…
若可能讀到長度為 0 的檔案時,建議將下列程式碼
WebForm.Response.BinaryWrite(System.IO.File.ReadAllBytes(FilePath))
改成 MSDN 的寫法
http://msdn.microsoft.com/en-us/library/system.web.httpresponse.binarywrite(v=vs.71).aspx
原因:System.ArgumentOutOfRangeException

這個網誌中的熱門文章

使用LM Studio輕鬆在本地端以API呼叫大語言模型(LLM)

VS Code的字體大小

使用 Dify 建立企業請假機器人

使用Qdrant向量資料庫實作語意相似度比對

使用C#開發LineBot(3) - 使用LineBotSDK發送Line訊息