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 <= 0then 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的处理关系不大,不再赘述.