在實際開發中,我們經常需要將圖片、可執行檔、影片、文件等大型二進位物件存入資料庫。Microsoft SQL Server 提供了 image 資料類型,可儲存高達 2 GB 的二進位資料。本文將示範如何透過 ADO.NET 搭配 SQL Server,實作檔案的寫入、讀取與另存新檔功能。
請在查詢分析器中執行以下 T-SQL 指令,建立名為 imgtable 的資料表:
CREATE TABLE [imgtable] (
[imgid] [int] IDENTITY(1,1) NOT NULL,
[imgname] [varchar](100) COLLATE Chinese_PRC_CI_AS NULL,
[imgData] [image] NULL,
PRIMARY KEY CLUSTERED ([imgid]) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
執行完成後,所選資料庫中將會多出一個 imgtable 資料表,包含自動遞增的識別碼、檔案名稱與二進位資料欄位。
以下是一個完整的 C# Windows Forms 範例,包含三個按鈕:
OpenFileDialog 選取檔案,讀取位元組陣列後以參數化 SQL 寫入。image 欄位轉為 MemoryStream 再建構 Bitmap 顯示於 PictureBox。Process.Start 呼叫系統關聯程式開啟。private void openFileDialog1_FileOk(object sender, CancelEventArgs e) {
string filename = openFileDialog1.FileName;
using (SqlConnection conn = new SqlConnection("server=192.168.2.200;integrated security=sspi;database=northwind"))
using (SqlCommand cmd = new SqlCommand("INSERT INTO imgtable VALUES (@imgname, @imgData)", conn)) {
cmd.Parameters.Add("@imgname", SqlDbType.VarChar, 100).Value = filename;
var pmImg = cmd.Parameters.Add("@imgData", SqlDbType.Image);
byte[] fileData;
using (FileStream fs = new FileStream(filename, FileMode.Open)) {
fileData = new byte[fs.Length];
fs.Read(fileData, 0, fileData.Length);
}
pmImg.Value = fileData;
conn.Open();
try { cmd.ExecuteNonQuery(); }
catch (Exception ex) { MessageBox.Show(ex.Message); }
}
}
private void button2_Click(object sender, EventArgs e) {
using (SqlConnection conn = new SqlConnection("server=192.168.2.200;integrated security=sspi;database=northwind"))
using (SqlCommand cmd = new SqlCommand("SELECT * FROM imgtable WHERE imgname LIKE '%bmp%'", conn)) {
conn.Open();
using (SqlDataReader dr = cmd.ExecuteReader()) {
if (dr.Read()) {
var sb = dr.GetSqlBinary(2); // 或 (byte[])dr[2]
using (MemoryStream ms = new MemoryStream(sb.Value)) {
pictureBox1.Image = new Bitmap(Bitmap.FromStream(ms));
}
}
}
}
}
private void button3_Click(object sender, EventArgs e) {
using (SqlConnection conn = new SqlConnection("server=192.168.2.200;integrated security=sspi;database=northwind"))
using (SqlCommand cmd = new SqlCommand("SELECT * FROM imgtable WHERE imgname LIKE '%doc'", conn)) {
conn.Open();
using (SqlDataReader dr = cmd.ExecuteReader()) {
if (dr.Read()) {
var sb = dr.GetSqlBinary(2);
string filename = @"C:\" + Path.GetFileName(dr.GetString(1));
File.WriteAllBytes(filename, sb.Value);
Process.Start(filename);
}
}
}
}
上述範例將整個檔案一次讀入記憶體陣列,適用於小型檔案。若檔案大小超過實體記憶體,或為超大型檔案(如影片),必須改用 分塊讀寫(Chunked I/O):
FileStream 搭配固定大小緩衝區(如 8KB~64KB)分段讀取。UPDATETEXT 或 .WRITE 子句分段寫入 image/varbinary(max) 欄位。FileStream / FileTable(SQL Server 2012+)將檔案存放於檔案系統,資料庫僅存路徑。此外,實務上建議:
using 區塊確保連線、資料流正確釋放。app.config/web.config),勿硬編碼。