摘要:文章主要介紹管理信息系統(tǒng)(MIS)中對(duì)圖像數(shù)據(jù)的存儲(chǔ)機(jī)制和存取方法。以visual basic為開(kāi)發(fā)工具,介紹了一種通過(guò)ADO Field 對(duì)象的GetChunk 方法和AppendChunk 方法來(lái)存取MIS 中的圖像數(shù)據(jù)的方法。
關(guān)鍵詞:BLOB;對(duì)象;GetChunk方法;AppendChunk方法
中圖分類號(hào):TP393文獻(xiàn)標(biāo)識(shí)碼:A文章編號(hào):1009-3044(2008)28-0044-02
A Way of Access Image Data with the VB in SQL Server
FU JieLI Chun-yan
(Southwest University of Science and Technology, Mianyang, 621010, China)
Abstract: This paper introduces the mechanism of MIS SQL Server memory and access image data. In accordance with Visual Basic, it present two kinds of method to access image data’s from MIS SQL Server ,GetChunk method and AppendChunk method which are provided by ADO Field object.
Key words: BLOB; object; GetChunk; AppendChunk
1 引言
在信息管理系統(tǒng),尤其是醫(yī)院的信息管理系統(tǒng)(MIS)中,圖像數(shù)據(jù)比如X光片、CT像片的保存是必不可少的,而且是非常重要。一方面,這些圖像數(shù)據(jù)在遠(yuǎn)程診療為準(zhǔn)確診斷病情提供了重要的依據(jù),另一方面,也為快速查閱病人資料提供了基本條件。
2 SQL Server中圖像數(shù)據(jù)的存儲(chǔ)機(jī)制
在醫(yī)院的信息管理系統(tǒng)中,由于系統(tǒng)的數(shù)據(jù)量巨大,我們采用SQL Server作為后臺(tái)數(shù)據(jù)庫(kù),以下我們簡(jiǎn)稱MIS SQL Server。 在一般的MIS中,對(duì)于小于 8000字節(jié)的圖像數(shù)據(jù)可以用二進(jìn)制型(binary、varbinary)來(lái)表示。但是在醫(yī)院的MIS系統(tǒng)中,要保存的一些醫(yī)學(xué)影像圖片都會(huì)大于 8000個(gè)字節(jié)。SQL Server提供了一種機(jī)制,能存儲(chǔ)每行大到 2G的二進(jìn)制對(duì)象(BLOB),這類對(duì)象可包括image、text和ntext三種數(shù)據(jù)類型。Image數(shù)據(jù)類型存儲(chǔ)的是二進(jìn)制數(shù)據(jù),最大長(zhǎng)度是 231-1 (2,147,483,647)字節(jié)[2-3]。
BLOB數(shù)據(jù)在MIS SQL Server系統(tǒng)中的存儲(chǔ)方式不同于普通的數(shù)據(jù)類型,對(duì)于普通類型的數(shù)據(jù)系統(tǒng)直接在用戶定義的字段上存儲(chǔ)數(shù)據(jù)值,而對(duì)于BLOB類型數(shù)據(jù),系統(tǒng)開(kāi)辟新的存儲(chǔ)頁(yè)面來(lái)存放這些數(shù)據(jù),表中BLOB類型數(shù)據(jù)字段存放的僅是一個(gè)16個(gè)字節(jié)的指針,該指針指向存放該條記錄的BLOB數(shù)據(jù)的頁(yè)面。
3 SQL Server中圖像數(shù)據(jù)的存取
在MIS SQL Server中,當(dāng)數(shù)據(jù)小于 8000字節(jié)時(shí),可以用普通的SQL操縱語(yǔ)句(SELECT、INSERT、UPDATE、DELETE)來(lái)完成對(duì)字段的操縱,當(dāng)數(shù)據(jù)大于8000個(gè)字節(jié)時(shí),SQL提供了 WRITETEXT 、READTEXT和UPDATETEXT這三個(gè)函數(shù)來(lái)讀取和修改數(shù)據(jù)。這三個(gè)函數(shù)的使用方法為:
1) WRITETEXT {table.column text_ptr}[WITH LOG] {data}
table.column為表中的字段,text_ptr為一個(gè)16個(gè)字節(jié)的指針,data為要寫(xiě)的數(shù)據(jù)值??蛇x參數(shù)WITH LOG表示是否要寫(xiě)入日志文件中。
例: DECLARE @ptrval binary(16)--指針
SELECT @ptrval = TEXTPTR(img_ct) FROM zy_ct WHERE id_ct = 20010101001
WRITETEXT zy_ct.img_ct @ptrval 0x024324142342134214213421421454353452341
2) READTEXT {table.column text_ptr offset size} [HOLDLOCK]
table.column為表中的字段,text_ptr為一個(gè)16個(gè)字節(jié)的指針,offset 為偏移量,即從第幾個(gè)字節(jié)開(kāi)始讀數(shù)據(jù),size為要讀的字節(jié)數(shù),HOLDLOCK 為在讀數(shù)據(jù)中是否充許其他用戶修改該數(shù)據(jù)。
例: DECLARE @ptrval varbinary(16)
SELECT @ptrval = TEXTPTR(img_ct) FROM zy_ct WHERE id_ct = 20010101001
READTEXT zy_ct.img_ct @ptrval 1 25
3) UPDATETEXT {table_name.dest_column_name dest_text_ptr}{NULL|insert_offset}
{ NULL | delete_length}[WITH LOG][ inserted_data| {table_name.src_column_name src_text_ptr}]
table_name.dest_column_name 為要修改的text, ntext, 或 image字段;
dest_text_ptr為指向其的指針;insert_offset為偏移量,對(duì)于text和image為從第幾開(kāi)始字節(jié)開(kāi)始寫(xiě),對(duì)于ntext為從第幾個(gè)字符(雙字節(jié))開(kāi)始寫(xiě);delete_length為從insert_offset開(kāi)始刪除delete_length長(zhǎng)度的字節(jié)(符),為0時(shí)不刪除,為NULL時(shí)為刪除從insert_offset開(kāi)始到結(jié)束的所有數(shù)據(jù)。要插入的數(shù)據(jù)為 inserted_data為,也可是表table_name的src_column_name字段中指針 src_text_ptr所指數(shù)據(jù)。
例: DECLARE @ptrval binary(16)
SELECT @ptrval = TEXTPTR(img_ct) FROM zy_ct WHERE id_ct = 20010101001
UPDATETEXT zy_ct.img_ct @ptrval 16 0x54345
這三個(gè)函數(shù)的使用比較復(fù)雜,雖然可以通過(guò)生成存貯過(guò)程來(lái)調(diào)用執(zhí)行,但有一個(gè)缺陷是在讀取數(shù)據(jù)時(shí),READTEXT函數(shù)讀取的數(shù)據(jù)無(wú)法直接傳遞回前端應(yīng)用程序。
4VB 6.0中圖像數(shù)據(jù)的存取
VB 6.0 的ADO Field 對(duì)象提供了GetChunk 方法和AppendChunk 方法來(lái)存取BLOB數(shù)據(jù)[1],這兩個(gè)函數(shù)實(shí)質(zhì)是通過(guò)API調(diào)用WRITETEXT 、READTEXT和UPDATETEXT這三個(gè)函數(shù),簡(jiǎn)化了調(diào)用的方法。
1) GetChunk 和AppendChunk方法
GetChunk 方法檢索其部分或全部長(zhǎng)二進(jìn)制或字符數(shù)據(jù)[4]。GetChunk 調(diào)用返回的數(shù)據(jù)將賦給“變量”。如果 Size 大于剩余的數(shù)據(jù),則 GetChunk 僅返回剩余的數(shù)據(jù)而無(wú)需用空白填充“變量”。如果字段為空,則 GetChunk 方法返回 Null。每個(gè)后續(xù)的 GetChunk 調(diào)用將檢索從前一次 GetChunk 調(diào)用停止處開(kāi)始的數(shù)據(jù)。但是,如果從一個(gè)字段檢索數(shù)據(jù)然后在當(dāng)前記錄中設(shè)置或讀取另一個(gè)字段的值,ADO 將認(rèn)為已從第一個(gè)字段中檢索出數(shù)據(jù)。如果在第一個(gè)字段上再次調(diào)用 GetChunk 方法,ADO 將把調(diào)用解釋為新的 GetChunk 操作并從記錄的起始處開(kāi)始讀取。Field 對(duì)象的第一個(gè) AppendChunk 調(diào)用將數(shù)據(jù)寫(xiě)入字段,覆蓋所有現(xiàn)有的數(shù)據(jù),隨后的 AppendChunk 調(diào)用則添加到現(xiàn)有數(shù)據(jù)。
由于系統(tǒng)資源總是有限的,如果一次讀(存)取大量數(shù)據(jù),可能會(huì)引起服務(wù)器、客戶機(jī)死機(jī)或是服務(wù)器的性能大大下降,因此使用這兩個(gè)函數(shù)時(shí),要將圖像數(shù)據(jù)進(jìn)行分段讀寫(xiě)。
2) 對(duì)大BLOB圖像存取的實(shí)現(xiàn)
寫(xiě)數(shù)據(jù)函數(shù)的實(shí)現(xiàn):寫(xiě)數(shù)據(jù)函數(shù)的實(shí)現(xiàn)方法主要是將文件分為若干相同大小的塊來(lái)讀寫(xiě),避免對(duì)大量文件的一次性讀寫(xiě)帶來(lái)網(wǎng)絡(luò)的擁塞和服務(wù)器負(fù)擔(dān)的加重。下面是核心代碼部分
Public Function AppendBlobFromFile(blobColumn As ADODB.Field, ByVal FileName) As Boolean
…..定義相應(yīng)的信息……
On Error GoTo ErrorHandle
AppendBlobFromFile = False
ChunkSize = 2048'限制每次讀取的塊大小為 2K
FileNumber = FreeFile '產(chǎn)生隨機(jī)的文件號(hào)
Open FileName For Binary Access Read As FileNumber'打開(kāi)圖像文件
DataLen = LOF(FileNumber) '獲得文件長(zhǎng)度
If IsNull(blobColumn) Then Exit Function
…..驗(yàn)證,以保證文件長(zhǎng)度不會(huì)為0……
Chunks = DataLen \\ ChunkSize'數(shù)據(jù)塊的個(gè)數(shù)
Fragment = DataLen Mod ChunkSize
If Fragment > 0 Then'先寫(xiě)零碎數(shù)據(jù)
ReDim ChunkAry(Fragment - 1)
Get FileNumber, , ChunkAry()'讀出文件
blobColumn.AppendChunk ChunkAry'調(diào)用AppendChunk函數(shù)寫(xiě)數(shù)據(jù)
End If
ReDim ChunkAry(ChunkSize - 1) '為數(shù)據(jù)塊開(kāi)辟空間
For lngI = 1 To Chunks'循環(huán)讀出所有數(shù)據(jù)塊
Get FileNumber, , ChunkAry()'讀出一塊數(shù)據(jù)
blobColumn.AppendChunk ChunkAry '在數(shù)據(jù)庫(kù)中增加數(shù)據(jù)塊
Next lngI
…..關(guān)閉數(shù)據(jù)文件,如果操作有誤,彈出相應(yīng)錯(cuò)誤消息…..
End Function
讀數(shù)據(jù)函數(shù)關(guān)鍵代碼的實(shí)現(xiàn),讀函數(shù),同樣是分塊讀取。核心代碼如下:
Public Function ReadbolbToFile(blobColumn As ADODB.Field, ByVal FileName) As Boolean
…….定義相關(guān)信息…..
…..讀取文件大小與上面相同……
DataLen = blobColumn.ActualSize '獲得圖像大小
If DataLen < 8 ThenExit Function'圖像大小小于8字節(jié)時(shí)認(rèn)為不是圖像信息
FileNumber = FreeFile '產(chǎn)生隨機(jī)的文件號(hào)
Open FileName For Binary Access Write As FileNumber'打開(kāi)存放圖像數(shù)據(jù)文件
Chunks = DataLen \\ ChunkSize'數(shù)據(jù)塊數(shù)
Fragment = DataLen Mod ChunkSize'零碎數(shù)據(jù)
If Fragment > 0 Then'有零碎數(shù)據(jù),則先讀該數(shù)據(jù)
ReDim ChunkAry(Fragment - 1)
ChunkAry = blobColumn.GetChunk(Fragment)
Put FileNumber, , ChunkAry'寫(xiě)入文件
End If
ReDim ChunkAry(ChunkSize - 1) '為數(shù)據(jù)塊重新開(kāi)辟空間
For lngI = 1 To Chunks'循環(huán)讀出所有塊
ChunkAry = blobColumn.GetChunk(ChunkSize) '在數(shù)據(jù)庫(kù)中連續(xù)讀數(shù)據(jù)塊
Put FileNumber, , ChunkAry() '將數(shù)據(jù)塊寫(xiě)入文件中
Next lngI
…..操作完畢,關(guān)閉文件,讀取錯(cuò)誤,給出相關(guān)信息…..
End Function
當(dāng)BLOB類型的字段為空時(shí),調(diào)用AppendChunk或 GetChunk函數(shù)將出錯(cuò)。此時(shí)如果想給該字段插入圖像數(shù)據(jù),應(yīng)該先使用 Update語(yǔ)句給該字段賦初值如0x0,以便數(shù)據(jù)庫(kù)系統(tǒng)為該字段分配一個(gè)頁(yè)面地址來(lái)存放BLOB數(shù)據(jù)。
4 結(jié)論
Microsoft SQL Server為保存大二進(jìn)制數(shù)據(jù)提供了存儲(chǔ)平臺(tái),Visual Basic 6.0為存取這種數(shù)據(jù)提供了靈活的接口。本文介紹的用VB接口存取 MIS SQL Server中大二進(jìn)制數(shù)據(jù)的方法,不但適用于圖像文件,同樣適用于其它類型的文件。該方法應(yīng)用于醫(yī)院管理系統(tǒng)的圖像存取中,在存取速度、對(duì)系統(tǒng)的性能影響等方面都取了滿意的效果。
參考文獻(xiàn):
[1] [美] Curtis Smith Michael Amundsen .Visual Basic 6.0 數(shù)據(jù)庫(kù)編程.陳海林,譯.北京:清華大學(xué)出版社.
[2] SQL Server對(duì)圖像數(shù)據(jù)的存儲(chǔ)機(jī)制介紹,http://database.ccidnet.com/art/1105/20070320/ 1040611_1.html.
[3] 圖像數(shù)據(jù)的數(shù)據(jù)庫(kù)存儲(chǔ)實(shí)現(xiàn),http://www.ibm.com/developerworks/cn/db2/library/ techarticles/dm-0807daiwei/index.html.
[4] [美] JEFFOEY P.MCMANUS.VISUAL BASIC6數(shù)據(jù)庫(kù)訪問(wèn)技術(shù)[M].趙軍鎖,龔波,李志等,譯.北京:機(jī)械工業(yè)出版社.