有時候我們需要把圖片、文檔、dll文件、等等,上傳的數據庫,然后當需要的時候再從數據庫中讀取到本地,下面我以上傳圖片為例,講解一下如何把本地的一張圖片上傳到數據庫,然后再從數據庫下載到本地。
工具:VS2010,Sql Server 2000。語言:C#。
像這樣的文件,我們上傳的時候都是以二進制的形式操作,在數據庫中對應的數據類型為image,我們只需要把本地文件轉為二進制形式,然后以image數據保存到數據庫就行。
Sql Server 2000自帶的數據庫Northwind,有一張表Categories,其中有一個字段Picture為image類型,我們就以它為例,上傳一張圖片到這個表中。
1 打開vs2010新建一個項目“Windows窗體應用程序”,在窗體Form1上放置兩個按鈕,分別改變文本為"上傳“ 和 "下載",添加對應的單擊事件。
2 新建一個類,這個類用來封裝對文件上傳和下載的功能調用,然后我們可以在前面的單擊事件中調用這個方法。下面是這個類的完整定義:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data.SqlClient; using System.Windows.Forms; using System.IO; using System.Data; namespace test { class UpDownLoad { public string categoryName; //下載時可以再外部指定文件名 private string description; private byte[] picture; public SqlConnection GetConn() //得到連接對象 { SqlConnection conn = new SqlConnection("Data Source =.;Initial Catalog = Northwind;user id = sa;"); try { conn.Open(); } catch (Exception e) { MessageBox.Show("連接數據庫失敗:{0}", e.Message); conn.Close(); } return conn; } private static string GetFilePath() //通過打開對話框得到文件路徑 { string filepath = ""; OpenFileDialog openfiledlg = new OpenFileDialog(); if (openfiledlg.ShowDialog() == DialogResult.OK) { filepath = openfiledlg.FileName; } return filepath; } private static Byte[] GetContent(string filepath) //將某路徑下的文件 轉化為 二進制代碼 { FileStream fs = new FileStream(filepath, FileMode.Open, FileAccess.Read); //打開文件流 Byte[] byData = new Byte[fs.Length]; //保存文件的字節數組 fs.Read(byData, 0, byData.Length); //讀取文件流 fs.Close();//釋放資源 return byData; } public void UpLoad() //上傳 { string filePath = GetFilePath();//得到文件路徑 FileInfo fi = new FileInfo(filePath);//文件信息對象 this.categoryName = fi.Name; //獲取文件名 this.description = "這是我上傳到數據庫的第一張照片"; this.picture = GetContent(filePath);//通過路徑獲取文件二進制形式 SqlConnection conn = GetConn(); string sqlstr = string.Format("insert into Categories(CategoryName,Description,Picture) values(@fileName,@descri,@pic)"); SqlCommand comm = new SqlCommand(sqlstr, conn); comm.Parameters.Add("fileName", SqlDbType.VarChar);//添加變量 comm.Parameters["fileName"].Value = this.categoryName; comm.Parameters.AddWithValue("descri", this.description);//添加變量 comm.Parameters.AddWithValue("pic", this.picture); if (comm.ExecuteNonQuery() == 1) { MessageBox.Show("添加一張照片成功。"); } conn.Close();//關閉數據庫 } public void DownLoad() //下載圖片 { if (categoryName == "") { MessageBox.Show("請先對下載的文件填寫文件名"); return; } SqlConnection conn = GetConn(); string sqlstr = string.Format("select * from Categories where CategoryName = @fileName"); SqlCommand comm = new SqlCommand(sqlstr, conn); comm.Parameters.AddWithValue("@fileName", this.categoryName); SqlDataReader dr = comm.ExecuteReader(); if (dr.HasRows) { if (dr.Read())//讀一行數據 { this.picture = (byte []) dr["Picture"]; FileStream fs = new FileStream(categoryName, FileMode.Create, FileAccess.Write); fs.Write(picture, 0, picture.Length); fs.Close();//一定要關閉,否則不會將流讀入文件 dr.Close(); conn.Close(); } }//if else { MessageBox.Show("沒有這個文件"); return; } } } }
3 如果這個類的命名空間與主程序的命名空間名不同,要在主程序添加引用:using test;
然后在前面的兩個單擊事件中分別添加如下代碼,
(1)在上傳按鈕對應的button1中先聲明一個對象,然后調用:
private void button1_Click(object sender, EventArgs e) { UpDownLoad updown = new UpDownLoad(); updown.UpLoad(); }
(2)在下載對應的button2中聲明一個對象,然后給要下載的文件賦值,再調用:
private void button2_Click(object sender, EventArgs e) { UpDownLoad updown = new UpDownLoad() ; updown.categoryName = "金河.jpg";//最好是自己剛才上傳的文件的名字 updown.DownLoad(); }
然后在本程序的Debug目錄下面就會出現從數據庫中下載到本地的圖片。
總結:最初我想把dll文件上傳到數據庫,然后通過從數據庫下載dll文件到本地實現程序的自動更新,但是當時下載的時候忘記關閉FileStream對象流,結果下載到的文件為空,后來又牽涉到很多其他的邏輯問題,后來感覺到很崩潰,不過當我靜下心來將問題簡單化(先實現最簡單的,不牽涉很多邏輯問題功能,然后在通過邏輯來調用功能),這樣子下來感覺問題簡單多了。學習的時候切忌浮躁。
