Delphi与Oracle中BLOB字段的操作(转)
Oracle将LOB分为两种:内部LOB和外部LOB。内部LOB包括CLOB,BLOB和NCLOB三种类型,它们的数据存储在数据库中,并且支持事务操作(提交,回滚,保存点);外部LOB只有BFILE一种类型,该类型的数据被存储在操作系统(OS)文件中,并且不支持事务操作。
其中,CLOB/NCLOB用于存储大批量字符数据,BLOB用于存储大批量二进制数据,而BFILE则存储着指向OS文件的指针.
其次:Delphi连接Oracle数据库
1.如果使用ADO方式进行联接,需要使用Oracle提供的驱动"oracle provider for ole DB",如果使用"microsoft ole db provider for oracle"在处理时会出现问题(提示无效的字段类型等)
2.最好使用ODAC进行与oracle数据库进行关联,虽然这是第三方控件,但它最大的优点是,在程序发布时不需要任何dll文件,相比ADO,BDE要简便很多,而且ODAC的使用还是很广的。
第三:用delphi编写clob,blob字段的读写等操作
1.建立测试表
create table ttt(id integer primary key,b blob,c clob);
2.存入测试数据(我为了方便直接插入一条)
insert into ttt values(1,'',''); //****注意,虽然这里可以正常执行,但我犯一个严重的错误为以后的操作埋下隐患*****//
commit;
3.打开delphi开在桌面上放置一上memo控件用来显示clob,与blob的内容(我这里只对blob进行说明)
插入数据Insert:
procedure TForm1.Button3Click(Sender: TObject);
var
vstream: TMemoryStream;
begin
vstream := TMemoryStream.Create;
memo1.Lines.SaveToStream(vstream);
adoquery1.SQL.Text := 'select * from TTT';
adoquery1.Open;
adoquery1.Append; // 写BLOB字段之前使 处于编辑状态。
adoquery1.FieldByName('ID').Value := 2;
TBlobField(adoquery1.FieldByName('b')).LoadFromStream(vstream);
adoquery1.Post;
end;
修改数据Edit:
procedure TForm1.Button1Click(Sender: TObject);
var
vstream: TMemoryStream;
begin
orasession1.StartTransaction;
vstream := TMemoryStream.Create;
memo1.Lines.SaveToStream(vstream);
with oraquery2 do
begin
close;
sql.text := ' select * from TTT where id=1';
open;
oraquery2.Edit;
TBlobField(FieldByName('b')).LoadFromStream(vstream);
post;
end;
orasession1.Commit;
end;
在这里出现的问题,在POST时提示字段类型等错误,在经过反复测试后,觉得代码上没有问题,不知其原因所在,唉...一点点查吧
将select * from TTT where id=1 换成select * from TTT where id=2;却没有问题,这样就想到了,id=1的记录是我手工insert的,
而id=2是程序保存的于时查了一下oracle中对于blob与clob字段的说明:对于clob与blob字段要利用DBMS包进行初始化,如这样:
insert into ttt values(1,empty_clob(),empty_blob())
删除id=1重新insert后,一切正常了。
总结:在网上也有相关的贴子讨论clob,blob字段显示数据不全的问题,其实都是因为对于oracle的字段有些不理解,进行数据库应用开发,常握数据库知识也很重要。
修改代码
var
ms,ms1: TMemoryStream; //Memory Stream for blob insert
t :tfilestream;
begin
//创建内存流并保存图片框中位图
ms := TMemoryStream.Create;
ms1 := TMemoryStream.Create;
ms1.LoadFromFile('d:\ABEJ12024111D802355Z.pdf');
ms1.Position:=0;
ms1.SaveToStream(ms);
//Image1.Picture.Graphic.SaveToStream(ms);
ms.Position:=0;
with adoquery1 do
begin
close;
sql.Clear;
sql.Add( 'update eygle_blob set FPIC=:sfz1 where FID=:xh1');
parameters.ParamByName('xh1').Value:= 1;
parameters.ParamByName('sfz1').LoadFromStream(ms,ftBlob);
ExecSQL;
end;
ms.Free;
ms1.free;
end
----查找文件夹下某种类型的文件
--- FindFileName---目录名 Filetpye==文件类型 Tstr --返回值
procedure TForm1.FindFile(FindFileName, Filetpye: string; Tstr: TStrings);
var
FSearchRec,
DSearchRec: TSearchRec;
FindResult: integer;
function IsDirNotation(ADirName: String): Boolean;
begin
Result := (ADirName = '.') or (ADirName = '..');
end;
begin
if FindFileName[Length(FindFileName)]<> '\' then
FindFileName:=FindFileName+'\';
FindResult := FindFirst(FindFileName+'*.*', faDirectory, DSearchRec);
//tstr.Add(FindFileName+fsearchrec.Name);
while FindResult = 0 do
begin
if ((DSearchRec.Attr and faDirectory) = faDirectory) and not
IsDirNotation(DSearchRec.Name) then
begin
FindFile(FindFileName+DSearchRec.Name,Filetpye,Tstr);
// tstr.Add(FindFileName+fsearchrec.Name);
end;
FindResult := FindNext(DSearchRec);
end;
FindResult := FindFirst(FindFileName+'*.*',faAnyFile+faHidden+
faSysFile,FSearchRec);
// tstr.Add(FindFileName+fsearchrec.Name);
try
while FindResult = 0 do
begin
//ShowMessage(FindFileName+fsearchrec.Name);
if Pos(Filetpye,FindFileName+fsearchrec.Name)>0 then
begin
tstr.Add(fsearchrec.Name+'='+FindFileName+fsearchrec.Name);
end;
FindResult := FindNext(FSearchRec);
end;
finally
FindClose(FSearchRec);
end;
Findclose(DSearchRec);
end;