前置準備
- 專案資料夾 `App_Data/Uploads/` (寫入權限 `IIS_IUSRS` / `ApplicationPoolIdentity`)。
- `web.config` 限制上傳大小:
<httpRuntime maxRequestLength="102400" /> (100MB,單位 KB)。
- 前端表單:
enctype="multipart/form-data"。
1. 檔案上傳
// .aspx
// .aspx.cs
protected void btnUpload_Click(object sender, EventArgs e)
{
if (!fuFile.HasFile) { lblMsg.Text = "請選擇檔案"; return; }
string ext = Path.GetExtension(fuFile.FileName).ToLower();
string[] allowed = { ".jpg", ".png", ".pdf", ".zip" };
if (!allowed.Contains(ext)) { lblMsg.Text = "副檔名不允許"; return; }
string safeName = $"{Guid.NewGuid():N}{ext}";
string savePath = Server.MapPath($"~/App_Data/Uploads/{safeName}");
try
{
fuFile.SaveAs(savePath);
lblMsg.Text = $"上傳成功:{safeName}";
// 可寫入資料庫記錄原始檔名、儲存名、大小、上傳者、時間
}
catch (Exception ex)
{
lblMsg.Text = "上傳失敗:" + ex.Message;
}
}
2. 檔案下載
// 方式一:直接連結 (靜態檔案/已知路徑)
下載
// 方式二:程式碼輸出 (權限控管、動態產生、大檔案斷點續傳)
public void DownloadFile(string storedName, string originalName)
{
string path = Server.MapPath($"~/App_Data/Uploads/{storedName}");
if (!File.Exists(path)) { Response.StatusCode = 404; return; }
Response.Clear();
Response.ContentType = "application/octet-stream";
Response.AddHeader("Content-Disposition", $"attachment; filename=\"{HttpUtility.UrlEncode(originalName, Encoding.UTF8)}\"");
Response.AddHeader("Content-Length", new FileInfo(path).Length.ToString());
Response.TransmitFile(path); // 高效輸出,不載入記憶體
Response.End();
}
3. 檔案刪除
protected void btnDelete_Click(object sender, EventArgs e)
{
string storedName = lstFiles.SelectedValue; // 假設 ListBox 儲存儲存名
if (string.IsNullOrEmpty(storedName)) return;
string path = Server.MapPath($"~/App_Data/Uploads/{storedName}");
try
{
if (File.Exists(path))
{
File.Delete(path);
// 同步刪除資料庫記錄
lblMsg.Text = "刪除成功";
BindFileList(); // 重新綁定列表
}
}
catch (Exception ex)
{
lblMsg.Text = "刪除失敗:" + ex.Message;
}
}
4. 取得檔案清單
private void BindFileList()
{
string dir = Server.MapPath("~/App_Data/Uploads/");
if (!Directory.Exists(dir)) return;
var files = new DirectoryInfo(dir).GetFiles()
.OrderByDescending(f => f.LastWriteTime)
.Select(f => new
{
Name = f.Name,
Size = f.Length,
Time = f.LastWriteTime.ToString("yyyy-MM-dd HH:mm"),
// 原始檔名需從資料庫查詢
})
.ToList();
gvFiles.DataSource = files;
gvFiles.DataBind();
}
安全性核心守則
| 風險 | 防禦措施 |
| 惡意副檔名 (.aspx, .exe) | 白名單驗證副檔名 + MIME 檢查 + 儲存時重新命名 (GUID) |
| 路徑遍歷 (../) | `Path.GetFileName` 只取檔名 + `Path.Combine` 組合路徑 |
| 大檔案 DoS | `maxRequestLength` / `requestLimits maxAllowedContentLength` 限制大小 |
| 直接存取上傳目錄 | 放在 `App_Data` (IIS 預設拒絕直接瀏覽) 或 `web.config` 設定 `` |
| 檔案名稱編碼攻擊 | 下載時 `HttpUtility.UrlEncode` 原始檔名 |
進階:大檔案分塊上傳與斷點續傳
- 前端:Plupload / Dropzone / Resumable.js 切片上傳。
- 後端:合併分塊、記錄上傳進度、支援 `Range` 標頭續傳下載。
- 雲端儲存:Azure Blob / AWS S3 / MinIO + 預簽名 URL 直傳,減輕 Web 伺服器頻寬。
總結
ASP.NET 檔案操作核心在於 **`Server.MapPath` 路徑解析**、**`FileUpload.SaveAs`/`File.Delete`/`DirectoryInfo.GetFiles` 基礎 API**、**`Response.TransmitFile` 高效下載**,以及**嚴格的白名單、重命名、路徑遍歷防禦**。建立完整的上傳/下載/刪除/列表 CRUD 流程,並同步資料庫記錄原始中繼資料,即構成企業級檔案管理模組基石。
- 上一篇文章: C# 類別初始化順序深度解析:欄位初始化與建構子執行的真相
- 下一篇文章: C# 透過 WMI 實現遠端電腦關機/重開機完整教學
Copyright ©
程式碼之家 All Rights Reserved