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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章