摘要:對SQL Server數(shù)據(jù)庫關(guān)系表中BLOB圖像數(shù)據(jù)的存儲(chǔ)技術(shù)和工作原理作了論述,介紹了數(shù)據(jù)流技術(shù)在處理圖像文件中的實(shí)現(xiàn)方法。最后給出了一個(gè)基于WEB2.0的BLOB圖像數(shù)據(jù)存儲(chǔ)的應(yīng)用實(shí)例。指出利用二進(jìn)制實(shí)現(xiàn)對大數(shù)據(jù)文件進(jìn)行存取,能更好地保證數(shù)據(jù)庫運(yùn)行的安全性、完整性和封裝性。
關(guān)鍵詞:BLOB;圖像存取;ASP.NET;數(shù)據(jù)流
中圖分類號(hào):TP391文獻(xiàn)標(biāo)識(shí)碼:A文章編號(hào):1009-3044(2008)19-30006-03
BLOB Data Storage Technology and Its Application in the WEB2.0
WANG Chun-ming, ZHU Xiao-hui, CHEN Sen-bo
(College of Computer Science and Technology, Nantong University, Nantong 226019, China)
Abstract: In this paper, the BLOB image data storage in the SQL Server database technology and working principle discussed, Then introduced the method to storage the image file with stream technology. At last it gives a BLOB data storage based on the WEB2.0 Application examples. Realize that the use of large data files access to the database to better guarantee the safety, integrity and encapsulation.
Key words: BLOB; Image Data; ASP.NET; Stream
對于數(shù)據(jù)庫中圖像數(shù)據(jù)的存取通常有兩種方法,即將圖片直接存儲(chǔ)在數(shù)據(jù)庫中或者將圖片存儲(chǔ)在文件系統(tǒng)中而僅將圖片文件的存儲(chǔ)路徑直接存在數(shù)據(jù)庫中。在大多數(shù)情況下,最好把圖片文件與其它數(shù)據(jù)一起直接存儲(chǔ)在數(shù)據(jù)庫中,這樣做具有易于管理、便于維護(hù)等優(yōu)點(diǎn),因?yàn)楫?dāng)BLOB與其他數(shù)據(jù)一起存儲(chǔ)在數(shù)據(jù)庫中時(shí),BLOB和數(shù)據(jù)表格是一起備份和恢復(fù)。這樣就降低了表格數(shù)據(jù)與BLOB數(shù)據(jù)不同步的機(jī)會(huì),而且降低了其他用戶無意中刪改了文件系統(tǒng)中BLOB數(shù)據(jù)位置的路徑和風(fēng)險(xiǎn)。另外,將數(shù)據(jù)存儲(chǔ)在數(shù)據(jù)庫中BLOB和其他數(shù)據(jù)的插入、更新和刪除都在同一個(gè)事務(wù)中實(shí)現(xiàn)。這樣就確保了數(shù)據(jù)的一致性和文件與數(shù)據(jù)庫之間的一致性。不再需要為文件系統(tǒng)中的文件單獨(dú)設(shè)置安全性。
當(dāng)然,在某些情況下,將圖片存儲(chǔ)在文件系統(tǒng)中將是更好的選擇,如使用圖片的應(yīng)用程序需要數(shù)據(jù)流性能,還有一些應(yīng)用程序只知道怎樣訪問文件等。
1 BLOB數(shù)據(jù)類型
BLOB是二進(jìn)制大對象(Binary Large Object)的首字母縮寫,用于將一些不定的大文件以二進(jìn)制流的形式存儲(chǔ)在數(shù)據(jù)庫中。這些不定的大文件通常是多媒體對象,如圖像(.jpg、.gif、.bmp)、視頻、聲音和一些文本文件,甚至是代碼片段。實(shí)際上,在一些數(shù)據(jù)庫系統(tǒng)中并不將其稱之為BLOB字段,如在SQL Server中,BLOB可以是text、ntext或者image數(shù)據(jù)類型。但從廣義上講,它們都屬于BLOB類型。在SQL Server中使用BLOB數(shù)據(jù)時(shí),每條記錄的數(shù)據(jù)量一般都遠(yuǎn)遠(yuǎn)超過了一個(gè)單獨(dú)記錄的8K的限制。
由于BLOB數(shù)據(jù)是數(shù)據(jù)量很大的數(shù)據(jù)類型,它會(huì)占用大量的硬盤空間、內(nèi)存和網(wǎng)絡(luò)資源,因此合理地設(shè)計(jì)包含有BLOB數(shù)據(jù)類型的屬性表,對提高存儲(chǔ)效率、查詢速度有很大的影響。二進(jìn)制大對象并不一定要存儲(chǔ)為text、ntext或者image數(shù)據(jù)類型,它們也可以作為varchar或者varbinary數(shù)據(jù)類型存儲(chǔ)在表格中。數(shù)據(jù)類型的選擇要估測將要存儲(chǔ)的BLOB的實(shí)際大小,如果數(shù)據(jù)不會(huì)超過8K,那么就選用varchar或者varbinary數(shù)據(jù)類型。如果這些大對象的尺寸超過8K,那么就選用text、ntext或者image數(shù)據(jù)類型。 SQLServer中有關(guān)字段數(shù)據(jù)類型對應(yīng)的存儲(chǔ)容量為:nchar可存儲(chǔ)4K字符;char可存儲(chǔ)8K字符;text可存儲(chǔ)大量文本,容量達(dá)2G左右;ntext可存儲(chǔ)大量文本,容量達(dá)1G左右;image可存儲(chǔ)圖像的二進(jìn)制數(shù)據(jù),容量達(dá)2G左右。
SQLServer中在使用text、ntext和image數(shù)據(jù)類型時(shí),這些數(shù)據(jù)在SQL Server系統(tǒng)中的實(shí)際存儲(chǔ)方式不同于普通的數(shù)據(jù)類型,對于普通類型的數(shù)據(jù)系統(tǒng)直接在用戶定義的字段上存儲(chǔ)數(shù)據(jù)值,而對于BLOB類型數(shù)據(jù),系統(tǒng)開辟新的存儲(chǔ)頁面來存放這些數(shù)據(jù),表中BLOB類型數(shù)據(jù)字段存放的僅是一個(gè)16個(gè)字節(jié)的指針,該指針指向相應(yīng)BLOB數(shù)據(jù)的實(shí)際存儲(chǔ)頁面。只是這個(gè)16個(gè)字節(jié)的指針和實(shí)際BLOB數(shù)據(jù)存儲(chǔ)頁面的管理都是在后臺(tái)處理的,對用戶是透明的。
2 數(shù)據(jù)流(Stream)
“流”是在程序和信息發(fā)送者或接收者之間建立的一個(gè)用于輸入/輸出數(shù)據(jù)的通道,它解決了由于數(shù)據(jù)源或數(shù)據(jù)宿的多樣性而帶來的輸入/輸出操作的復(fù)雜性與程序員所希望的輸入/輸出操作的相對統(tǒng)一和簡單之間的矛盾。“流”可以被理解為一條“管道”,可以可看作為流動(dòng)的數(shù)據(jù)緩沖區(qū)。“管道”在讀寫數(shù)據(jù)時(shí)能夠應(yīng)付數(shù)據(jù)源或數(shù)據(jù)宿的多樣性,消化掉因數(shù)據(jù)源或數(shù)據(jù)宿的多樣性帶來的數(shù)據(jù)讀/寫的全部復(fù)雜性,使得程序輸入/輸出時(shí)原本直接對數(shù)據(jù)源或數(shù)據(jù)宿的復(fù)雜操作轉(zhuǎn)化為對“管道”的統(tǒng)一而簡單的操作,這樣就大大化解列輸入/輸出的復(fù)雜性,減輕了程序員的負(fù)擔(dān)。
當(dāng)需要從數(shù)據(jù)源讀取數(shù)據(jù)時(shí),建立一個(gè)與數(shù)據(jù)源相連的 “流(stream)”,然后從“流”中依次讀取數(shù)據(jù);當(dāng)需要把數(shù)據(jù)寫入到目標(biāo)時(shí),建立一個(gè)與目標(biāo)端相連的“流”,然后通過“流”將數(shù)據(jù)依次寫入到目標(biāo)中。程序和外界的數(shù)據(jù)交換都可以通過流實(shí)現(xiàn)。無論涉及輸入/輸出的數(shù)據(jù)源和數(shù)據(jù)宿是什么,只要建立了“流”,用戶就不必再關(guān)心數(shù)據(jù)來自何方或送往何處,程序中輸入/輸出操作的復(fù)雜性就大大降低了。所有輸入/輸出操作都轉(zhuǎn)換為對“流”的操作。圖1說明了圖像文件在SQLServer的存儲(chǔ)與顯示工作原理。
圖1 SQLServer BLOB數(shù)據(jù)存儲(chǔ)與顯示原理圖
C#的FileStream類提供的Read()方法和Write()方法可用來存取BLOB數(shù)據(jù),這兩個(gè)函數(shù)實(shí)質(zhì)是通過從流中讀取字節(jié)塊并將該數(shù)據(jù)寫入給定緩沖區(qū)中和使用從緩沖區(qū)讀取的數(shù)據(jù)將字節(jié)塊寫入流,F(xiàn)ileStream類位于 System.IO 命名空間。
3 訪問BLOB數(shù)據(jù)的應(yīng)用實(shí)例
本實(shí)例給出了在WEB2.0中如何將圖像文件直接保存到數(shù)據(jù)庫表中以及如何將數(shù)據(jù)庫中的圖像數(shù)據(jù)讀取并在web頁面上顯示出來。實(shí)例中 SQLServer數(shù)據(jù)庫中BLOB數(shù)據(jù)表的結(jié)構(gòu)如表1所示:
表1 SQLServer數(shù)據(jù)庫BLOB表結(jié)構(gòu)
3.1 向SQL Server數(shù)據(jù)庫存儲(chǔ) BLOB圖像數(shù)據(jù)
首先建立一個(gè)指向上載文件的流對象,使用該流對象的Read()方法將圖像文件轉(zhuǎn)為字節(jié)數(shù)組,再使用ADO.NET將圖像的字節(jié)數(shù)組存入SQLServer數(shù)據(jù)庫的image字段中。上傳圖像BLOB數(shù)據(jù)的.NET設(shè)計(jì)頁面如圖2所示,程序中采用了靜態(tài)連接類Dbcon連接相應(yīng)數(shù)據(jù)庫。
頁面中的 “上傳”按鈕的C#代碼如下:
SqlConnection con= DBCon.createConnection();
Stream imgDataStream = FileUpload1.PostedFile.InputStream;
int imgDataLen = FileUpload1.PostedFile.ContentLength;
string photoName = txtName.Text;
byte[] photoImg = new byte[imgDataLen];
int n = imgDataStream.Read(photoImg, 0, imgDataLen);
string sql= \"INSERT INTO [photo] ( [photoName], [photoImg]) \"
+ \"VALUES ( @photoName, @photoImg ) \";
SqlCommand command = new SqlCommand(sql, con);
command.Parameters.Add(new SqlParameter(\"@photoName\", photoName));
command.Parameters.Add(new SqlParameter(\"@photoImg\", photoImg));
con.Open();
command.ExecuteNonQuery();
通過HttpPoastedFile類的FilcName屬性、ContentType屬性、ContentLength屬性可分別得到上傳文件的絕對路徑、文件類型、文件字節(jié)數(shù)。相應(yīng)參數(shù)設(shè)置好后執(zhí)行一個(gè)ExecuteNonQuery()方法,將本地已轉(zhuǎn)為字節(jié)數(shù)組的圖像數(shù)據(jù)插入到SQLServer數(shù)據(jù)庫中。
■
圖2 上傳圖像BLOB數(shù)據(jù)的設(shè)計(jì)頁面圖
程序中數(shù)據(jù)流(Stream)的Read()方法的格式是:“int Read(byte[] array, int offset,int count);”,它的功能是從流中讀取字節(jié)塊并將該數(shù)據(jù)寫入給定緩沖區(qū)字節(jié)數(shù)組中。數(shù)組array中字節(jié)偏移量offset和(offset+count-1)之間的值被從當(dāng)前源中讀取的字節(jié)替換。Offset為寫入的起始位置,count為最多讀取的字節(jié)數(shù),方法的返回值是實(shí)際讀取的字節(jié)數(shù),只有在到達(dá)流的末尾后,read()方法才返回零,否則,read()在返回前始終至少從流讀取一個(gè)字節(jié)。由于進(jìn)行read()操作后,數(shù)組的寫入指針始終指向array的當(dāng)前位置,所以如果需要連續(xù)的讀取流數(shù)據(jù),則read()方法中的 offset 始終是0。
3.2從SQL Server讀取并顯示 BLOB圖像數(shù)據(jù)
對于數(shù)據(jù)庫中存儲(chǔ)的二進(jìn)制圖像數(shù)據(jù)文件,并不能夠像字符型、日期型等規(guī)則數(shù)據(jù)那樣可以直接以行、列的形式在表格控件中顯示出來,必須經(jīng)過特殊處理才能顯示。這時(shí),需要建立一個(gè)指向內(nèi)存字節(jié)數(shù)組的內(nèi)存流(MemoryStream類)對象,通過該內(nèi)存流將數(shù)據(jù)庫中二進(jìn)制圖像數(shù)據(jù)讀入內(nèi)存中的字節(jié)數(shù)組中,然后可以再創(chuàng)建一個(gè)指向本地圖像文件的文件流,使用文件流的Write()方法將字節(jié)數(shù)組寫入本地圖像文件;或者直接將內(nèi)存數(shù)組發(fā)送至web頁面顯示。在web頁面上直接顯示圖像BLOB數(shù)據(jù),簡單的實(shí)現(xiàn)方法是設(shè)計(jì)兩個(gè)頁面,一個(gè)是頁面用于顯示圖像,另一個(gè)頁面用于從數(shù)據(jù)庫獲取圖像。圖3顯示了在.NET中直接顯示圖像的設(shè)計(jì)頁面。
■
圖3 顯示圖像BLOB數(shù)據(jù)的設(shè)計(jì)頁面圖
在直接顯示圖像的頁面(displayimg.aspx)中,放置了有關(guān)的控件,其中“顯示圖片”按鈕的C#代碼只有一行,該行代碼的作用是將getimg.aspx頁獲取的圖片作為本頁中Image1控件的ImageUrl屬性,從而在本頁中顯示出來,該行C#代碼如下:
this.Image1.ImageUrl = \"getimg.aspx?PhotoID=\"+this.DropDownList1 .Text ;// getimg.aspx負(fù)責(zé)提取數(shù)據(jù)庫中的圖片,然后用二進(jìn)制輸出至http主體,最終交給displayimg.aspx頁面的Image1控件顯示。
從數(shù)據(jù)庫中獲取指定PhotoID的圖片由頁面getimg.aspx實(shí)現(xiàn),該頁面的Page_Load()方法的C#代碼如下:
protected void Page_Load(object sender, EventArgs e)
{ SqlConnection connection = DBCon.createConnection();
connection.Open();
int photoId = Convert.ToInt32(Request.QueryString[\"PhotoID\"]);
string sql = \"SELECTphotoImg FROM Photos WHERE photoID = \" + @photoId;
SqlCommand command = new SqlCommand(sql, connection);
command.Parameters.Add(new SqlParameter(\"@photoId\", photoId));
object result = command.ExecuteScalar();
Stream stream = new MemoryStream((byte[])result);
const int buffersize = 1024 * 16;
byte[] buffer = new byte[buffersize];
int count = stream.Read(buffer, 0, buffersize);
while (count > 0)
{Response.OutputStream.Write(buffer, 0, count);
count = stream.Read(buffer, 0, buffersize);
}
}
這里采用ADO.NET訪問數(shù)據(jù)庫,創(chuàng)建內(nèi)存流讀取數(shù)據(jù)庫中的BLOB圖像數(shù)據(jù),寫入http內(nèi)容主體,該頁面中的圖像最終在displayimg.aspx 頁面中顯示。上述代碼均在VS2005(C#)、SQLServer2000環(huán)境下調(diào)試通過。
4 結(jié)束語
將圖像數(shù)據(jù)直接存儲(chǔ)在數(shù)據(jù)庫中,是目前圖像數(shù)據(jù)庫技術(shù)發(fā)展的主流,SQLServer為保存BLOB提供了存儲(chǔ)平臺(tái),VS2005為存取這種數(shù)據(jù)提供了靈活的接口。在存儲(chǔ)BLOB數(shù)據(jù)到SQL Server中時(shí),需要根據(jù)BLOB數(shù)據(jù)量、使用效率等綜合考慮、靈活選擇。文章針對大二進(jìn)制數(shù)據(jù)(BLOB)的數(shù)據(jù)庫管理,從存儲(chǔ)方式、處理技術(shù)、訪問效率和數(shù)據(jù)安全等方面進(jìn)行了深入探討,介招了BLOB型數(shù)據(jù)的存儲(chǔ)方法和采用的編程思想。這些技術(shù)的使用,不僅可以保證圖像數(shù)據(jù)的一致性和安全性,還可以提高圖像數(shù)據(jù)的可用性和可伸縮性。
參考文獻(xiàn):
[1] 王春明.基于.NET的分布式系統(tǒng)研究[J].蘭州大學(xué)學(xué)報(bào),2005(6):524-526.
[2] 楊勇.數(shù)據(jù)庫系統(tǒng)中BLOB對象的管理[J].微電子學(xué)與計(jì)算機(jī),2006(7):147-149.
[3] 黃天云.基于Blob和嵌入SQL的數(shù)據(jù)庫外殼程序設(shè)計(jì)與實(shí)現(xiàn)[J].計(jì)算機(jī)工程與設(shè)計(jì),2007(11):81-83.
[4] 李勇平.ASP.NET 2.0(C#)基礎(chǔ)教程[M].北京:清華大學(xué)出版社,2008,1.