Delphi中有关Blob的几个常见问题
星空朗朗 2002-08-22 11:51:18 在用Delphi进行数据库编程,使用Blob字段时,经常会遇到一些问题。我把使用Blob时的常见问题总结了一下,在这里和大家一起分享和探讨:
1.如何对Blob字段进行读写?
Blob的读写一般通过流,也可以直接从文件读出数据和保存数据到文件。
写入Blob的代码如下:
Query.SQL.Clear;
Query.Sql.Add('INSERT INTO 表名 (...,Blob字段名,...) VALUES (...,:Blob,...)');
Query.ParamByName(Blob)).LoadFromStream(Stream);
//还可以用方法LoadFromFile()直接保存文件中的数据
Query.SQL.ExecSQL;
从字段读出代码如下:
Query.Close;
Query.SQL.Clear;
Query.SQL.Add('SELECT ...,Blob字段名,... FROM 表名 WHERE ...');
Query.Open;
TBlobField(Query.SQL.FieldByName(Blob字段名)).SaveToStream(Stream);
//或(Query.ParamByName(Blob字段名) as TBlobFiedl).SaveToStream(Stream);
//或Stream=TBlobFieldStream.Create(TBlobField(Query.SQL.FieldByName(Blob字段名)),bmRead);
//保存到文件用SaveToFile(文件名)
2.如何显示和编辑Blob?
由于数据的类型可能千变万化,所以,采用OLE方式是较方便的选择。我们可以在程序中放置一个OLE控件,用于显示、编辑各种BLOB数据。那么,问题的关键就是BLOB数据如何入库,以及数据库如何与OLE控件之间传递数据。
第一种解决方案是在库中直接保存原始数据。具体方法如下:
BLOB数据的入库:要把BLOB数据入库,不能向普通的数据那样直接赋值;而是利用BLOB字段的LoadFromfile方法。采用这个方法,可以直接将各种数据的数据文件存入数据库。代码如下:
AblobField.LoadFromfile(aFileName);
这时数据库与OLE控件间的数据传递也要通过数据文件。即,BLOB字段先将数据存盘;然后,OLE从将数据文件中创建所需要的OLE对象。代码如下:
AblobField.SaveToFile(aFileName);
AOleContainer.CreateObjectFromFile(aFileName);
注意:OLE对象不能直接使用LoadFromFile方法,因为,数据库中存放的BLOB对象的格式是文件原来的格式,而不是OLE格式,是不能直接读取的。直接读取将导致运行错误。
第二种方案是在库中以OLE格式保存数据。具体方法如下:
本方案的不同之处,在于数据入库前先进行格式的转换。格式的转换是通过OLE控件完成的。即,先创建OLE对象,然后入库。示例代码如下:
AOleContainer.CreateObjectFromFile(aFileName);
AoleContainer.SaveToFile(tmpFileName);
ABlobField.LoadFromfile(tmpFileName);
这样作的好处是,由于库中直接存储的是OLE格式,所以,在库与OLE控件之间的数据传递将非常方便。在这种情况下,可以通过文件直接传递:数据字段先将数据存到一个临时文件中,然后,OLE控件从临时文件中读取。即:
AblobField.SaveToFile(aFileName);
AOleContainer.LoadFromFile(aFileName);
另外,还可以通过内存流来完成。使用内存流,可减少磁盘操作,大大提高运行效率。即:
AblobField.SaveToStream(aStream);
AOleContainer.LoadFromStream(aStream);
下面是一个简单的例子。
本例中,采用Paradox数据库。库中有两个字段,一个是字符型,另一个是BLOB型。我们在主Form上放一个OLE控件用于编辑及转换数据。一个Table控件操作数据库。源代码如下:
//打开一个数据文件、创建OLE对象、将对象数据存入数据库
procedure TForm1.LoadBtnClick(Sender: TObject);
var
fn: string;
begin
if OpenDialog1.Execute then begin //打开文件
fn := ExtractFileName(OpenDialog1.FileName);
OleContainer1.CreateObjectFromFile(OpenDialog1.FileName, False); //创建OLE对象
OleContainer1.SaveToFile("tmp"); //将OLE数据存入临时文件
Table1.Append;
Table1FileName.AsString := fn;
Table1ABlob.LoadFromFile("tmp"); //将OLE数据存入数据库
Table1.post;
end;
end;
//定义此方法用于显示当前记录中的OLE对象
procedure TForm1.Table1AfterScroll(DataSet: TDataSet);
begin
if not Table1ABlob.IsNull then begin
Table1ABlob.SaveToFile("tmp"); //数据存入临时文件
OleContainer1.LoadFromFile("tmp"); //从临时文件中读取OLE对象
end;
end;
3.如何保存和显示JEPG格式图象数据?
TImage不能识别JEPG格式的图象数据,涉及jpg图片的操作(显示、存数据库等)要用TJPGImage类!
下面是一个简单的例子(数据库与上面一个例子相同):
//打开、显示JPG图片,添加图象数据到数据库
procedure TForm1.Button3Click(Sender: TObject);
Var
JPGImage:TjpegImage;
Bitmap:TBitmap;
Stream : TMemoryStream;
FileName:String;
ExtName: string;
begin
JPGImage:=TJpegImage.Create;
//打开图象文件
if OpenPictureDialog1.Execute Then
begin
FileName:=OpenPictureDialog1.FileName;
ExtName:=AnsiUpperCase(ExtractFileExt(FileName)); //后缀名
//JPGImage加载图象。对两种类型的图象文件:.BMP和.JPG分别处理
if ExtName='.BMP' then
begin
Bitmap:=TBitmap.Create;
Bitmap.LoadFromFile(FileName);
JPGImage.Assign(Bitmap);
JPGImage.Compress; //压缩成JPEG格式
Bitmap.Free;
end;
if ExtName='.JPG' Then
JPGImage.LoadFromFile(FileName);
//JPG图象保存到数据库,要以MemoryStream为中介
Stream:= TMemoryStream.Create ;
JPGImage.SaveToStream(Stream);
table1.append;
table1FileName.asstring:=ExtractFileName(FileName);
table1Blob.LoadFromStream(Stream);
table1.Post;
Image1.Picture.Assign(JPGImage);
Stream.Free ;
end;
end;
//显示图象
procedure TForm1.Table1AfterScroll(DataSet: TDataSet);
var
Stream : TStream;
JPGImage : TJpegImage;
begin
JPGImage:=Tjpegimage.Create;
if not table1Blob.isNull Then
begin
Stream:=TBlobStream.Create(Table1Blob,bmRead);
JPGImage.LoadFromStream(stream);
Image1.Picture.Assign(JPGImage);
Stream.Free;
end
else
Image1.Picture.Assign(Nil);
JPGImage.Free;
end;
另外还有两个问题我还没有找到答案:
1.Blob超过1M时报错;
2.Blob大于32M时的读写问题(详见http://www.csdn.net/expert/topic/956/956009.xml?temp=.3377191)。
希望大家提出更多意见和建议