1. 程式人生 > >PB大文字(Blob)物件處理

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的處理關係不大,不再贅述。