前端頁面 (Upload.aspx)
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Upload.aspx.cs" Inherits="Demo.Upload" %>
<!DOCTYPE html>
<html>
<body>
<form id="form1" runat="server" enctype="multipart/form-data">
<asp:FileUpload ID="fuFile" runat="server" />
<asp:Button ID="btnUpload" runat="server" Text="上傳" OnClick="btnUpload_Click" />
<br /><br />
<asp:ListBox ID="lbFiles" runat="server" Rows="10" Width="300px" AutoPostBack="true" OnSelectedIndexChanged="lbFiles_SelectedIndexChanged" />
<br />
<asp:LinkButton ID="lbDownload" runat="server" Text="下載選取檔案" OnClick="lbDownload_Click" Visible="false" />
<asp:LinkButton ID="lbDelete" runat="server" Text="刪除選取檔案" OnClick="lbDelete_Click" Visible="false" ForeColor="Red" />
<br /><br />
<asp:Label ID="lblMsg" runat="server" ForeColor="Green" />
</form>
</body>
</html>
後端程式碼 (Upload.aspx.cs)
using System;
using System.IO;
using System.Web.UI.WebControls;
namespace Demo
{
public partial class Upload : System.Web.UI.Page
{
private const string UploadFolder = "~/Uploads/";
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack) BindFileList();
}
// 1. 繫結檔案列表
private void BindFileList()
{
string physPath = Server.MapPath(UploadFolder);
if (!Directory.Exists(physPath)) Directory.CreateDirectory(physPath);
lbFiles.Items.Clear();
foreach (string file in Directory.GetFiles(physPath))
{
lbFiles.Items.Add(new ListItem(Path.GetFileName(file), file));
}
UpdateButtonState();
}
private void UpdateButtonState()
{
bool hasSelection = lbFiles.SelectedIndex >= 0;
lbDownload.Visible = hasSelection;
lbDelete.Visible = hasSelection;
}
// 2. 上傳
protected void btnUpload_Click(object sender, EventArgs e)
{
if (!fuFile.HasFile)
{
lblMsg.Text = "請選擇檔案";
return;
}
try
{
string physPath = Server.MapPath(UploadFolder);
string fileName = Path.GetFileName(fuFile.FileName);
string savePath = Path.Combine(physPath, fileName);
// 防止同名覆蓋:可加時間戳或 GUID
if (File.Exists(savePath))
{
string ext = Path.GetExtension(fileName);
string name = Path.GetFileNameWithoutExtension(fileName);
fileName = $"{name}_{DateTime.Now:yyyyMMddHHmmss}{ext}";
savePath = Path.Combine(physPath, fileName);
}
fuFile.SaveAs(savePath);
lblMsg.Text = $"上傳成功:{fileName}";
BindFileList();
}
catch (Exception ex)
{
lblMsg.Text = "上傳失敗:" + ex.Message;
}
}
// 3. 選取檔案事件
protected void lbFiles_SelectedIndexChanged(object sender, EventArgs e)
{
UpdateButtonState();
}
// 4. 下載
protected void lbDownload_Click(object sender, EventArgs e)
{
string filePath = lbFiles.SelectedValue;
if (File.Exists(filePath))
{
string fileName = Path.GetFileName(filePath);
Response.Clear();
Response.ContentType = "application/octet-stream";
Response.AddHeader("Content-Disposition", $"attachment; filename=\"{fileName}\"");
Response.TransmitFile(filePath);
Response.End();
}
else
{
lblMsg.Text = "檔案不存在";
BindFileList();
}
}
// 5. 刪除
protected void lbDelete_Click(object sender, EventArgs e)
{
string filePath = lbFiles.SelectedValue;
try
{
if (File.Exists(filePath))
{
File.Delete(filePath);
lblMsg.Text = "刪除成功";
}
else
{
lblMsg.Text = "檔案已不存在";
}
}
catch (Exception ex)
{
lblMsg.Text = "刪除失敗:" + ex.Message;
}
BindFileList();
}
}
}
關鍵技術點總結
| 功能 | 核心 API | 注意事項 |
| 上傳 | FileUpload.SaveAs | 表單需 enctype="multipart/form-data";httpRuntime maxRequestLength 限制大小 (預設 4MB) |
| 列表 | Directory.GetFiles | 搭配 Server.MapPath 轉換虛擬路徑 |
| 下載 | Response.TransmitFile | 大檔案不佔記憶體;Content-Disposition: attachment 強制下載 |
| 刪除 | File.Delete | 需處理檔案鎖定、權限不足例外 |
安全性強化清單
- 副檔名白名單:僅允許
.jpg, .pdf, .docx 等,拒絕 .exe, .aspx, .ashx 等可執行類型。
- 檔案內容驗證:讀取 Magic Number (檔頭位元組) 確認真實格式,防止偽裝副檔名。
- 儲存路徑隔離**:上傳目錄設為 非 Web 可執行目錄** (如
App_Data 或網站根目錄外),防止上傳腳本被執行。
- 檔名重命名**:使用 GUID 或時間戳重命名,避免路徑遍歷 (
../../../) 與同名覆蓋。
- 大小限制**:
web.config 設定 <httpRuntime maxRequestLength="10240" /> (單位 KB) 與 <security><requestFiltering><requestLimits maxAllowedContentLength="10485760" /></requestFiltering></security> (IIS 7+,單位 Bytes)。
- 權限最小化**:應用程式池身分僅擁有上傳目錄寫入權限,無系統目錄權限。
- 病毒掃描**:整合 ClamAV 或 Windows Defender 掃描上傳檔案。
進階擴充建議
- 非同步上傳:
async/await + HttpPostedFileBase.InputStream.CopyToAsync (MVC/Core)。
- 分塊上傳/斷點續傳:Plupload、FineUploader、Tus 協定。
- 檔案預覽:圖片縮圖、PDF.js、Office Online Viewer。
- 雲端儲存:Azure Blob Storage、AWS S3、MinIO,本地僅存暫存。
- 資料庫記錄:檔案元資料 (原始檔名、儲存路徑、上傳者、時間、大小、雜湊值) 存入 DB,檔案系統僅存實體內容。