將上傳圖片以二進位 (BLOB) 形式直接儲存於 SQL Server varbinary(MAX) 欄位,適合小型圖片、需交易一致性、備份還原簡單的場景。
CREATE TABLE [dbo].[UploadedImages] (
[Id] INT IDENTITY(1,1) PRIMARY KEY,
[FileName] NVARCHAR(255) NOT NULL,
[ContentType] NVARCHAR(50) NOT NULL,
[FileSize] INT NOT NULL,
[ImageData] VARBINARY(MAX) NOT NULL,
[UploadTime] DATETIME DEFAULT GETDATE()
);
<asp:FileUpload ID="fuImage" runat="server" />
<asp:Button ID="btnUpload" Text="上傳" OnClick="btnUpload_Click" runat="server" />
<asp:Label ID="lblMsg" runat="server" ForeColor="Red" />
protected void btnUpload_Click(object sender, EventArgs e)
{
if (!fuImage.HasFile)
{
lblMsg.Text = "請選擇檔案";
return;
}
// 1. 驗證副檔名
string ext = Path.GetExtension(fuImage.FileName).ToLower();
string[] allowed = { ".jpg", ".jpeg", ".png", ".gif", ".bmp" };
if (!allowed.Contains(ext))
{
lblMsg.Text = "僅允許 JPG/PNG/GIF/BMP 格式";
return;
}
// 2. 驗證檔案大小 (例: 2MB)
if (fuImage.PostedFile.ContentLength > 2 * 1024 * 1024)
{
lblMsg.Text = "檔案不得超過 2MB";
return;
}
// 3. 讀取二進位資料
byte[] fileBytes = fuImage.FileBytes; // 直接取得 byte[],簡潔高效
// 4. 存入資料庫 (參數化查詢防注入)
string sql = @"INSERT INTO UploadedImages (FileName, ContentType, FileSize, ImageData)
VALUES (@FileName, @ContentType, @FileSize, @ImageData)";
using (var conn = new SqlConnection(connStr))
using (var cmd = new SqlCommand(sql, conn))
{
cmd.Parameters.Add("@FileName", SqlDbType.NVarChar, 255).Value = fuImage.FileName;
cmd.Parameters.Add("@ContentType", SqlDbType.NVarChar, 50).Value = fuImage.PostedFile.ContentType;
cmd.Parameters.Add("@FileSize", SqlDbType.Int).Value = fileBytes.Length;
cmd.Parameters.Add("@ImageData", SqlDbType.VarBinary, -1).Value = fileBytes; // -1 = MAX
conn.Open();
int rows = cmd.ExecuteNonQuery();
lblMsg.Text = rows > 0 ? "上傳成功!" : "上傳失敗";
lblMsg.ForeColor = rows > 0 ? System.Drawing.Color.Green : System.Drawing.Color.Red;
}
}
public class ImageHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
string idStr = context.Request.QueryString["id"];
if (!int.TryParse(idStr, out int id)) return;
string sql = "SELECT ContentType, ImageData FROM UploadedImages WHERE Id = @Id";
using (var conn = new SqlConnection(connStr))
using (var cmd = new SqlCommand(sql, conn))
{
cmd.Parameters.AddWithValue("@Id", id);
conn.Open();
using (var reader = cmd.ExecuteReader())
{
if (reader.Read())
{
string contentType = reader.GetString(0);
byte[] data = (byte[])reader["ImageData"]; // 或 reader.GetSqlBytes(1).Buffer
context.Response.Clear();
context.Response.ContentType = contentType;
context.Response.BinaryWrite(data);
context.Response.End();
}
}
}
}
public bool IsReusable => false;
}
<!-- 列表頁 -->
<asp:Repeater ID="rptImages" runat="server">
<ItemTemplate>
<img src='ImageHandler.ashx?id=<%# Eval("Id") %>' width="150" />
<br /><%# Eval("FileName") %>
</ItemTemplate>
</asp:Repeater>
| 優點 | 缺點 |
|---|---|
| 資料完整性:資料庫備份即含圖片 | 資料庫體積快速膨脹,影響備份/還原速度 |
| 權限控管容易:透過資料列層級安全性 | 效能較差:大量讀取二進位資料佔用連線池、記憶體 |
| 刪除/更新具原子性 (交易) | 無法利用 CDN/瀏覽器快取 (每次經由 Handler 處理) |
| 避免檔案系統權限、路徑問題 | 不適合大檔 (>1MB) 或高併發存取 |
Url、FileName、Size、ContentType 等中繼資料。FileTable,結合檔案系統流式存取優勢。Cache-Control: public, max-age=31536000、ETag 支援瀏覽器快取。資料庫存圖雖簡單,但擴展性有限,建僅用於小型專案、內部系統、圖片數量少且需強一致性的場景。