1引言
隨著計算機的普及,數據庫應用程序越來越得到廣泛的應用,帶圖像的數據庫應用程序已成了數據庫應用程序不可缺少的一部分,如何將圖像信息存儲到數據庫中、如何用開發工具實現對圖形數據庫的存取等問題已成程序設計者必須解決的問題,如何解決上述問題就成了本文討論的重點。
2在Access數據庫中存儲圖像信息的方法
在Access數據庫中存儲圖像的方法很多,例如:用OLE對象存儲圖像信息和用文本存儲圖像信息等,其中用OLE對象存儲圖像信息是將圖像嵌入到數據庫中,這樣的好處是當數據庫或者原來圖像的位置發生變化時程序不需要做特殊的處理,但用OLE對象存儲圖像信息的數據庫會隨著圖像的增多運行速度逐漸變慢並且占用的存儲空間急劇增大,而用文本存儲圖像信息是用文本字段存放圖像的文件名,並將數據庫中用到的圖像存放到指定的文件夾中,這種方法的好處是數據庫占用的存儲空間小並且運行速度快。
3用VB.NET對圖片信息進行存取的方法
為了介紹上述方法的實現,本人先在Access中分別建立了名為DataBase1.mdb和DataBase2.mdb的學生信息數據庫,數據庫中都有一個名為Information表,其中一個包含了名為name的文本型字段和名為picture的OLE對象型字段,另一個包含了名為name和picture的兩個文本型字段。然後在VB.NET中設計一個如圖1所示的窗體,並添加一個名為OpenFileDialog1的OpenFileDialog控件。
圖1 窗體的設計界面
3.1用OLE對象存儲圖片信息
3.1.1總的設計思路
使用OLE對象存儲圖片信息最關鍵的問題就是如何將PictureBox控件中的圖像信息與OLE對象型字段的內容關聯起來,這裡可以考慮將PictureBox對象中的圖像文件讀成內存流,用SQL語句插入或更新到OLE對象字段中以二進制形式存儲,當從數據庫中讀取該字段時,將PictureBox對象的圖像源設置為來自內存流。
3.1.2代碼實現
(1)引入命名空間。由於在程序中用到MemoryStream類和與Access數據庫操作相關的類,所以在程序一開始的地方加入以下兩個語句引入命名空間:
Imports System.io
Imports System.Data.OleDb
(2)創建連接字符串。用Dim OleDbConnection1 As New OleDbConnection語句創建一個窗體級變量,在窗體的Load事件中設置連接字符串:OleDbConnection1.ConnectionString = "Data Source=""(數據庫的存放路徑)"";Provider=""Microsoft.Jet.OLEDB.4.0"""
(3)為“上傳相片”按鈕添加代碼。當點擊“上傳相片”按鈕時彈出打開文件對話框,將在打開文件對話框中選中的圖片文件作為PictureBox對象的圖像源,相關代碼如下所示:
If Me.OpenFileDialog1.ShowDialog() = DialogResult.OK Then
picPicture.Image = Image.FromFile(Me.OpenFileDialog1.FileName)
End If
(4)將pictureBox對象中的圖像信息轉換成無符號的字節數組。先用Save方法將PictureBox對象中的圖像信息保存到內存流對象TempMemoryStream中,然後用TempMemoryStream對象的GetBuffer方法返回從其創建此流的無符號字節數組。
Private Function GetImage() As Byte()
Dim TempMemoryStream As New MemoryStream
picPicture.Image.Save(TempMemoryStream, picPicture.Image.RawFormat)
Dim TempImage() As Byte = TempMemoryStream.GetBuffer
TempMemoryStream.Close()
Return TempImage
End Function
(5)將OLE對象字段的內容顯示在PictureBox控件中。先用CType函數將OLE對象字段的值轉化為字節數組類型,然後用上述所得到的字節數組作為MemoryStream類構造函數的參數來創建MemoryStream對象,最後將PictureBox對象的圖像源設置為來源於內存流,相關代碼如下所示:
Dim arrPicture() As Byte = CType(InformationTable.Rows(i)("picture"), Byte())
Dim TempMemoryStream As New MemoryStream(arrPicture)
picPicture.Image = Image.FromStream(TempMemoryStream)
(6)為插入、添加和刪除按鈕添加代碼。插入、添加和刪除這三個模塊的設計思路基本一致:先創建一個OleDbCommand對象,然後設置 OleDbCommand對象要連接的數據源和執行的SQL語句,最後調用ExecuteNonQuery方法執行SQL語句。由於三個模塊的代碼相似,下面只介紹插入按鈕的代碼:
Dim InsertCommand As New OleDbCommand
InsertCommand.Connection = OleDbConnection1
InsertCommand.CommandText = "insert into information(name,picture) values(@Name,@Picture)"
InsertCommand.Parameters.Add("@Name", OleDb.OleDbType.VarChar, 0, "name")
InsertCommand.Parameters.Add("@Picture", OleDb.OleDbType.VarBinary, 0, "picture")
InsertCommand.Parameters("@Name").Value = txtName.Text
InsertCommand.Parameters("@Picture").Value = GetImage()
OleDbConnection1.Open()
InsertCommand.ExecuteNonQuery()
OleDbConnection1.Close()
3.2用文本存儲圖片信息
3.2.1總的設計思路
用文本存儲圖片信息是在存儲圖像時只將圖像文件的文件名保存在數據庫中,並將圖像文件存放到指定的文件夾(picture文件夾)下,當浏覽記錄時將指定文件夾下對應文件名的圖像顯示在PictureBox控件中。
在設計時我們應該注意:本程序模擬的是一個學生信息系統,一條記錄對應一個圖像文件,為了避免指定文件夾存放多余的圖像文件,在一開始數據庫為空時指定文件夾也沒有任何文件,當添加或修改記錄時才將對應的圖像文件拷貝到指定文件夾中,當修改或刪除記錄時也應該刪除不需要的圖像文件。
3.2.2代碼實現
(1)引入命名空間。由於在程序中用到與Access數據庫操作相關的類和File類,所以在程序一開始的地方加入以下語句引入命名空間:
Imports System.Data.OleDb
Imports System.io
(2)為窗體的Load事件添加代碼。先獲取當前程序的運行路徑和picture文件夾的路徑,然後創建與數據庫的關聯,將相關數據從數據源提取到DataSet中,最後在窗體中顯示數據庫的內容。部分代碼如下:
Dim CurrentPath As String = Directory.GetCurrentDirectory'獲取當前程序的運行路徑
Path = CurrentPath + "picture" '獲取文件夾picture對應的路徑
OleDbConnection1.ConnectionString = "Data Source=""(數據庫的存放路徑)"";Provider=""Microsoft.Jet.OLEDB.4.0"""
OleDbConnection1.Open()
Dim SelectCommand As New OleDbCommand("select * from Information", OleDbConnection1)
OleDataAdapter1.SelectCommand = SelectCommand
OleDataAdapter1.Fill(DataSet1, "Information")'將滿足上面查詢條件的內容填充到DataSet1中
OleDbConnection1.Close()
ShowFirstRecord()'顯示第一條記錄
(4)為“上傳相片”按鈕添加代碼。將在打開文件對話框中選中的圖片文件作為PictureBox對象的圖像源,同時獲取該圖片文件的文件名和存放路徑。
獲取在打開文件對話框中選中的文件名的部分代碼如下所示:
index = Me.OpenFileDialog1.FileName.LastIndexOf("")' index存放文件路徑中最後一個""的位置
FileNameLength = Me.OpenFileDialog1.FileName.Length - index - 1 ' FileNameLength存放文件名的長度
PictureFileName = Me.OpenFileDialog1.FileName.Substring(index + 1, FileNameLength) ' PictureFileName存放在打開文件對話框中選中的文件的文件名
獲取在打開文件對話框中選中的文件的路徑(不包含文件名)的代碼如下所示:
NewPictureFilePath = Me.OpenFileDialog1.FileName.Substring(0, OpenFileDialog1.FileName.Length - FileNameLength)
(5)為“插入記錄”按鈕添加代碼。先將要插入的圖片文件拷貝到指定的文件夾下,如果要插入的圖片已經存放在指定文件夾下則不需要拷貝,如果新插入的圖片文件名在指定文件夾中已經存在,則應該對新插入的圖片重新命名;然後將新建的記錄添加到表中並更新數據源;最後顯示第一條記錄。相關代碼如下所示:
'1)如果在打開文件對話框中選中的文件的路徑與picture文件夾的路徑不同,則將在打開文件對話中選中的圖片拷貝到文件夾picture中
If NewPictureFilePath.CompareTo(Path) <> 0 Then
Dim OldPictureFileName As String = NewPictureFileName '將選中的圖片的文件名存在OldPictureFileName中
'如果選中的圖片文件名與picture文件夾中的圖片名相同,請重新命名
While File.Exists(Path + NewPictureFileName)
NewPictureFileName = InputBox("你選擇的圖片文件名在'picture'文件夾中已存在,請在下面文本框中重新命名該圖片文件,文件名要求包含後綴名,如1.jpg", "提示")
End While
'將在打開文件對話中選中的圖片拷貝到文件夾picture中
File.Copy(NewPictureFilePath + OldPictureFileName, Path + NewPictureFileName)
End If
'2)將記錄插入到表中
Dim InsertCommand As New OleDbCommand
InsertCommand.Connection = OleDbConnection1
InsertCommand.CommandText = "insert into information2(name,picture) values(@Name,@Picture)"
InsertCommand.Parameters.Add("@Name", OleDb.OleDbType.VarChar, 0, "name")
InsertCommand.Parameters.Add("@Picture", OleDb.OleDbType.VarChar, 0, "picture")
InsertCommand.Parameters("@Name").Value = txtName.Text
InsertCommand.Parameters("@Picture").Value = NewPictureFileName
OleDbConnection1.Open()
InsertCommand.ExecuteNonQuery()
OleDbConnection1.Close()
'3)顯示第一條記錄,目的是更新數據集
ShowFirstRecord()
(6)為“刪除記錄”按鈕添加代碼。先刪除picture文件夾中對應的圖片文件,然後刪除當前記錄並更新數據源,最後顯示第一條記錄。部分代碼如下所示:
'1)刪除picture文件夾中對應的相片(假設一張相片只對應一條記錄) picPicture.Image.Dispose() '釋放picPicture控件image中的所有資源
File.Delete(Path + PictureFileName)
'2)刪除當前記錄
Dim DeleteCommand As New OleDbCommand
DeleteCommand.Connection = OleDbConnection1
DeleteCommand.CommandText = "delete from information2 where name=@Name and picture=@Picture"
DeleteCommand.Parameters.Add("@Name", OleDb.OleDbType.VarChar, 0, "name")
DeleteCommand.Parameters.Add("@Picture", OleDb.OleDbType.VarChar, 0, "picture")
DeleteCommand.Parameters("@Name").Value = txtName.Text
DeleteCommand.Parameters("@Picture").Value = PictureFileName
OleDbConnection1.Open()
DeleteCommand.ExecuteNonQuery()
OleDbConnection1.Close()
'3)顯示第一條記錄,目的是更新數據集
ShowFirstRecord()
(7)為“修改記錄”按鈕添加代碼。如果修改前和修改後的圖片不一樣,則刪除原有圖片,將新的圖片拷貝到指定目錄上,然後修改記錄並更新數據源。部分代碼如下所示:
'1)如果修改前和修改後的圖片不一樣,則刪除原有圖片
If (NewPictureFilePath + NewPictureFileName).CompareTo(Path + PictureFileName) <> 0 Then
picPicture.Image.Dispose()
File.Delete(Path + PictureFileName)
End If
'2)如果在打開文件對話框中選中的文件的路徑與picture文件夾的路徑不同,則將在打開文件對話中選中的圖片拷貝到文件夾picture中,代碼與“插入記錄”的代碼相同,這裡省略。
'3)修改記錄
Dim ChangeCommand As New OleDbCommand
ChangeCommand.Connection = OleDbConnection1
ChangeCommand.CommandText = "update information2 set name=@Name,picture=@Picture where 編號=@Id"
ChangeCommand.Parameters.Add("@Name", OleDb.OleDbType.VarChar, 0, "name")
ChangeCommand.Parameters.Add("@Picture", OleDb.OleDbType.VarChar, 0, "picture")
ChangeCommand.Parameters.Add("@Id", OleDb.OleDbType.Integer, 0, "編號")
ChangeCommand.Parameters("@Name").Value = txtName.Text
ChangeCommand.Parameters("@Picture").Value = NewPictureFileName
ChangeCommand.Parameters("@Id").Value = id
OleDbConnection1.Open()
ChangeCommand.ExecuteNonQuery()
OleDbConnection1.Close()
'4)顯示第一條記錄,目的是更新數據集
ShowFirstRecord()
4小結
從程序的測試結果看,當兩個數據庫都存儲相同的信息時,用OLE對象存儲圖像信息的數據庫所占的存儲空間是用文本存儲圖像信息的數據庫和存放圖像的picture文件夾所占的存儲空間之和的一倍,並且對用OLE對象存儲圖像信息的數據庫進行訪問的時間很大程度是由圖像的大小決定,圖像越大訪問時間越長,而對用文本存儲圖像信息的數據庫中的不同圖像大小的記錄進行訪問的時間基本都相同,並且比前者快得多。因此,從數據占用的存儲空間和對數據庫的訪問效率上看,第二種方法的優勢更大。