首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> ASP.NET 基礎

ASP.NET 實作伺服器目錄檔案列表與下載功能完整教學

     編輯:ASP.NET 基礎

在企業內部系統或檔案管理平台中,常需要讓使用者瀏覽伺服器特定資料夾下的檔案並提供下載。本文將完整示範如何使用 ASP.NET 讀取伺服器目錄檔案、綁定至 Repeater 控制項顯示,並實作安全的檔案下載功能,包含中文檔名編碼處理與錯誤攔截機制。

功能需求與架構概覽

  • 掃描指定伺服器資料夾(如 ~/uploads/)下的所有檔案
  • 將檔案清單繫結至 Repeater 控制項呈現
  • 使用者點擊下載連結時,透過 CommandName 識別動作並傳遞檔名參數
  • 下載時正確設定 HTTP 標頭,支援中文檔名、大檔案傳輸與斷點續傳基礎

步驟一:掃描目錄並綁定檔案清單

在 Page_Load 或專門的資料繫結方法中,使用 System.IO 命名空間下的 DirectoryInfo 與 FileInfo 類別掃描檔案:

string dirPath = HttpContext.Current.Server.MapPath("~/uploads/");

if (Directory.Exists(dirPath))
{
    DirectoryInfo dir = new DirectoryInfo(dirPath);
    // 取得所有檔案,可依需求過濾副檔名,如 "*.pdf"
    FileInfo[] files = dir.GetFiles("*.*");
    
    // 建立臨時 DataTable 作為 Repeater 資料來源
    DataTable dt = new DataTable();
    dt.Columns.Add("FileName");
    
    foreach (FileInfo fileInfo in files)
    {
        DataRow dr = dt.NewRow();
        dr["FileName"] = fileInfo.Name;
        dt.Rows.Add(dr);
    }
    
    Repeater1.DataSource = dt;
    Repeater1.DataBind();
}

Repeater 前端範例(.aspx):

<asp:Repeater ID="Repeater1" runat="server" OnItemCommand="Repeater1_ItemCommand">
    <ItemTemplate>
        <div class="file-item">
            <span><%# Eval("FileName") %></span>
            <asp:LinkButton ID="lnkDownload" runat="server" 
                CommandName="down" 
                CommandArgument='<%# Eval("FileName") %>'
                Text="下載" />
        </div>
    </ItemTemplate>
</asp:Repeater>

步驟二:實作檔案下載邏輯

在 Repeater1_ItemCommand 事件中處理下載請求,核心在於正確設定 Response 標頭:

protected void Repeater1_ItemCommand(object source, RepeaterCommandEventArgs e)
{
    if (e.CommandName == "down")
    {
        try
        {
            string fileName = e.CommandArgument.ToString();
            string virtualPath = "~/uploads/" + fileName;
            string physicalPath = Server.MapPath(virtualPath);
            
            // 檢查檔案是否存在
            FileInfo file = new FileInfo(physicalPath);
            if (!file.Exists)
            {
                Response.Write("<script>alert('找不到下載的檔案');</script>");
                return;
            }
            
            // 清除輸出緩衝區
            Response.Clear();
            Response.ClearHeaders();
            Response.ClearContent();
            
            // 設定 Content-Type 為二進位串流,強制瀏覽器彈出下載對話框
            Response.ContentType = "application/octet-stream";
            
            // 關鍵:使用 UrlEncode 處理中文檔名,避免瀏覽器顯示亂碼
            // 必須指定 Encoding.UTF8 確保各瀏覽器相容
            string encodedFileName = HttpUtility.UrlEncode(file.Name, System.Text.Encoding.UTF8);
            Response.AddHeader("Content-Disposition", "attachment; filename=" + encodedFileName);
            
            // 告知瀏覽器檔案大小,支援下載進度顯示
            Response.AddHeader("Content-Length", file.Length.ToString());
            
            // 將檔案直接寫入輸出串流(適合中小型檔案)
            Response.WriteFile(physicalPath);
            Response.Flush();
            Response.End();
        }
        catch (Exception ex)
        {
            // 記錄錯誤日誌(建議使用 log4net 或 NLog)
            // Log.Error("檔案下載失敗", ex);
            Response.Write("<script>alert('下載過程發生錯誤');</script>");
        }
    }
}

關鍵技術細節深度解析

1. 中文檔名編碼處理

直接在 Content-Disposition 中使用中文檔名會導致 IE、Edge、Chrome 等瀏覽器顯示亂碼或截斷。標準做法是使用 HttpUtility.UrlEncode 搭配 UTF-8 編碼:

string encodedFileName = HttpUtility.UrlEncode(file.Name, Encoding.UTF8);
Response.AddHeader("Content-Disposition", $"attachment; filename={encodedFileName}");

進階做法可參考 RFC 5987,同時提供 filename* 參數以支援現代瀏覽器:

Response.AddHeader("Content-Disposition", 
    $"attachment; filename={encodedFileName}; filename*=UTF-8''{encodedFileName}");

2. Response.WriteFile vs Response.TransmitFile

  • Response.WriteFile:將檔案讀入記憶體再輸出,適合小檔案(< 100MB),大檔案易造成記憶體壓力。
  • Response.TransmitFile:使用 Windows 核心模式傳輸,不佔用 ASP.NET 工作執行緒記憶體,支援超大檔案(GB 級),建議生產環境優先使用。

3. 大檔案下載優化建議

若系統需支援大檔案(> 500MB),建議改用分塊傳輸:

  • 設定 Response.BufferOutput = false 關閉緩衝
  • 使用 FileStream 讀取檔案區塊,搭配 Response.OutputStream.Write 輸出
  • 每寫入一區塊呼叫 Response.Flush()
  • 定期檢查 Response.IsClientConnected,若用戶中斷連線則提早終止釋放資源

詳細大檔案下載實作請參考本系列下一篇:ASP.NET 大檔案分塊下載最佳實踐。

4. 安全性考量

  • 路徑遍歷防護: 嚴禁直接信任使用者輸入的路徑,必須使用 Path.GetFileName 只取檔名,並搭配 Server.MapPath 限定在特定資料夾下。
  • 權限控管: 下載前應驗證使用者身分與授權(如 [Authorize] 或自訂權限檢查)。
  • 檔案類型驗證: 可維護白名單副檔名,禁止下載 .exe、.bat、.aspx 等可執行檔。

常見問題與除錯技巧

現象可能原因解決方案
下載檔案為 0 bytes 或損壞Response 輸出前有其他內容(如空白行、HTML)下載前呼叫 Response.Clear()、Response.ClearHeaders()、Response.ClearContent()
中文檔名亂碼未使用 UrlEncode 或編碼不一致統一使用 HttpUtility.UrlEncode(filename, Encoding.UTF8)
大檔案下載中斷 / 記憶體爆增使用 WriteFile 讀入完整檔案改用 TransmitFile 或分塊串流輸出
UpdatePanel 非同步下載失效檔案下載需完整 Postback,不支援 AJAX 部分更新將下載按鈕設為 PostBackTrigger 或置於 UpdatePanel 外

總結

本文示範了 ASP.NET 實作伺服器目錄檔案列表與下載的標準流程:DirectoryInfo 掃描 → DataTable 繫結 → Repeater 呈現 → ItemCommand 處理下載 → Response 標頭設定 → WriteFile/TransmitFile 輸出。掌握中文檔名編碼、大檔案傳輸策略與安全性防護,即可建構穩健的檔案下載功能。實務上建議封裝為共用的 FileHelper.DownloadFile() 靜態方法,減少重複代碼並統一錯誤處理邏輯。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved