天天看点

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的处理关系不大,不再赘述。