天天看點

PB大文本(Blob)對象處理

**Blob類型的資料用來儲存象大文本和圖象之類的資料,這種資料長度很大、幾乎沒有限制。而在PB中,沒有長度限制的對象僅此一種類型,是以它有特殊的處理方法。

Blob類型的資料沒有邊界限制,可以儲存一些普通類型的字段不能儲存的資訊。

以下情況下考慮使用Blob類型的字段:

a)要儲存OLE對象(如圖形、聲音等)時;

b)将大型的二進制對象存入資料庫中時:

c)當文本對象過大,以至于一般的字元串函數無法對其操作時;

d)資料庫中有PB不能支援的資料類型時。

普通類型的字段使用資料視窗,通過調用函數Update和Commit事務管理語句就可以保

存資料了。但Blod類型的資料非常龐大,是以這種類型字段的更新不能像普通的字段,隻能用其特有的語句進行更新。Updateblob的文法格式如下:

Updateblob 表名 set Blob類型字段名 =:Blob類型變量 where 子句;

上面的文法和Update文法類似,除了使用關鍵字Updateblob外,其他和Update文法都相同。

普通類型的字段顯示是通過資料視窗,調用Retrieve即可。但是,由于Blob類型的資料非常龐大,用戶端的主緩存區開辟多麼大的空間都不合适。PowerBuilder的解決方法是,不允許在資料視窗中放置Blob類型的字段,而是提供專用的提取Blob類型資料的語句。該語句文法如下:

Selectblob Blob類型的列名 into :Blob類型變量 from 表名 where 子句;

上面的文法同Select語句類似,隻是使用了關鍵字Selectblob。另外,Selectblob和

Updateblob中的where子句都必須隻能傳回一行資料,也就是說,一次隻能處理一個Blob類

型的資料。

關于Blob類型的處理隻能通過上面的兩個語句來進行。不像普通類型的字段那樣資料

的更新可以通過Insert語句實作。是以,在使用Updateblob語句之前,符合where子句條件

的資料已經存在了,并且隻存在一條資料。是以,如果想把大文本或者圖像等Blob類型的資料寫入資料庫,必須首先插入這條記錄的其他部分,然後再通過修改記錄的方式将Blob類型資料寫入。

*因為大文本對象特别龐大,當使用Updateblob時應該将事務對象的Autocommit設定為True,這很容易了解。因為這麼龐大的資料量要求一次送出,顯然多大的緩沖記憶體都不合适,隻能讓事務對象在合适的時候自動送出了。

*DBMS中的資料類型可以在PowerScript中與Blob資料類型相對應,如在Oracle對應為longraw,raw。在MS SQL Server中對應為image,text。在DB2/2中對應為N/A。

**執行個體

假設在一個應用系統中,進行合同管理時要儲存合同的原樣,以便以後的責任審查。用圖像掃描裝置将合同掃描成圖形檔案,以圖像方式儲存到資料庫中,這就涉及了Blob類型的處理該軟體實作時,最重要的首先是圖像的儲存,然後是圖像的顯示問題。

假設在視窗w_contract上左邊是dw_1,在dw_1上顯示合同中的相關資料,使用者選擇不同的資料行時,對應的合同文本顯示在picture控件p_1上;使用者點選“錄入合同文本”按鈕時打開w_htwb_input視窗選擇合同文本對應的圖形檔案名稱,傳回後根據該檔案大小進行相關處理,并儲存到資料庫中。

資料視窗dw_1從contract資料表中提取資料,該資料視窗中不包括Blob類型的字段htwb,其主鍵為合同編号(htbh)。當資料視窗的行焦點改變時讀取該行中的合同文本,并顯示在picture控件p_1上。在資料視窗的rowfocuschanged事件中編寫腳本如下:

blob lbb_pic //用來儲存圖檔

string ls_htbh //用來儲存合同編号

if currentrow <= 0 then return

this.selectrow(0,false)

this.selectrow(currentrow,true)

setpointer(hourglass!)

ls_htbh = trim(this.getitemstring(currentrow,"htbh"))

if len(ls_htbh) > 0 then

selectblob htwb into :lbb_pic from contract where htbh = :ls_htbh;

//讀取圖象

if len(lbb_pic) > 0 then

p_1.setpicture(lbb_pic)

else

beep(2)

messagebox("提示",ls_htbh + "号合同沒有錄入合同文本!",information!)

end if

enf if

setpointer(arrow!)

在“錄入合同文本”按鈕的clicked事件中編寫腳本,彈出另外一個response類型的視窗w_htwb_input,讓使用者在該視窗中選擇要錄入的合同文本的圖形檔案,傳回後讀取該檔案并儲存到資料庫中。因為fileread函數一次讀取的檔案不能大于32KB,如果大于32KB就隻能以32KB為機關分多次讀取。腳本如下:

string ls_pic,ls_htbh

integer li_i,li_fileptr,li_loops

long ll_filelen,ll_bytes_read,ll_new_pos

blob lbb_read,lbb_total

if dw_1.modifiedcount() <> 0 then //確定其他資料已經送出

beep(2)

messagebox("提示","請先儲存再錄入合同文本!",information!)

return

else //如果沒有修改過,則判斷是否有合同号(如果沒有合同号則肯定不能送出)

ls_htbh = trim(dw_1.getitemstring(dw_1.getrow(),"htbh"))

if len(ls_htbh) <= 0 then

beep(2)

messagebox("提示","必須首先錄入合同好,才能錄入合同文本!",stopsign!)

return

end if

end if

open(w_htbh_input) //打開合同文本錄入視窗

ls_pic = message.stringparm

setpointer(hourglass!)

ll_filelen = filelength(ls_pic) //擷取檔案的長度

li_fileptr = fileopen(ls_pic,streammode!,read!,lockread!)

if li_fileptr <> -1 then

beep(2)

messagebox("錯誤","圖形檔案打開錯誤!",information!)

return

end if

if_filelen > 32766 then

li_loops = (li_filelen - 1)/32766 + 1

else

li_loops = 1

end if

for li_i = 1 to li_loops

ll_bytes_read = fileread(li_fileptr,lbb_read)

lbb_total = lbb_total + lbb_read

ll_new_pos = ll_new_pos + ll_bytes_read

fileseek(li_fileptr,ll_new_pos,frombeginning!)

next

fileclose(li_fileptr)

setpicture(p_1,lbb_total)

sqlca.autocommit = true

updateblob contract set htwb = :lbb_total where htbh = :htbh_str;

sqlca.autocommit = false

if sqlca.sqlcode = -1 then

messagebox("失敗",sqlca.sqlerrtext)

elseif sqlca.sqlcode = 100 then

messagebox("失敗",ls_htbh + "号合同沒有找到!",information!)

end if

在視窗w_htwb_input視窗中,提供讓使用者選擇檔案名稱的功能。這部分的腳本比較簡單

并且也和Blob的處理關系不大,不再贅述。