各们大虾:在下在开发中碰到一个问题,就是如何高效存取SQL Server 2000中BLOB字段。请各位高手赐教。
问题背景:在开发基于SQL Server 2000的一个传统c/S数据库应用程序时,一个用户表中有多个image(即BLOB)类型的字段(现以三个字段bFacePhoto、bSidePhoto、bAllPhoto来说明问题),用于存放三幅图(JPG格式的,已经过减肥,每幅图大小不等,最小的45KB,最大的100多KB),存取现在都是没有问题的,问题的核心是在取出相应的记录时,有相当的延时。我用的是开发工具是delphi 7,用ADO访问数据库,现在我想加入ClientDataSet和DataSetProvider,并设置DataSetProvider 的poFetchBlobsOnDemand为True,想利用这个缓冲数据集在解决读取图像时严重延时的问题,我想在列记录时先不取出BLOB信息,等用户想查看图像时,就再读取相应记录的BLob信息,我调用了Fill_Picture(DataSet)过程完成图像读取,代码如下:
procedure TFrmNew.Fill_Picture(DataSet: TDataSet);
var
sFileName1, sFileName2, sFileName3: string;
tempstream1, tempstream2, tempstream3: TStringStream;
tempjpeg1, tempjpeg2, tempjpeg3: TJPEGImage;
begin
if not DataSet.IsEmpty then
begin
try
tempstream1 := TStringStream.Create(' ');
tempstream2 := TStringStream.Create(' ');
tempstream3 := TStringStream.Create(' '); if (not Dataset.FieldByName('bFacePhoto').IsNull) then
begin
TBlobField(Dataset.FieldByName('bFacePhoto')).SaveToStream(tempstream1);
tempstream1.Position := 0;
if not Assigned(tempjpeg1) then
tempjpeg1 := TJPEGImage.Create;
tempjpeg1.LoadFromStream(tempstream1);
Img1.Picture.Bitmap.Assign(tempjpeg1);
sFileName1 := ExtractFilePath(Application.ExeName) + 'tmpFaceBlob';
sFileName1 := sFileName1 + '.Jpg';
img1.Picture.SaveToFile(sFileName1);
end
else
begin
Img1.Picture.Graphic := nil; //清空正面照图像
end;
if (not Dataset.FieldByName('bSidePhoto').IsNull) then
begin
TBlobField(Dataset.FieldByName('bSidePhoto')).SaveToStream(tempstream2);
tempstream2.Position := 0;
if not Assigned(tempjpeg2) then
tempjpeg2 := TJPEGImage.Create;
tempjpeg2.LoadFromStream(tempstream2);
Img2.Picture.Bitmap.Assign(tempjpeg2);
sFileName2 := ExtractFilePath(Application.ExeName) + 'tmpSideBlob';
sFileName2 := sFileName2 + '.Jpg';
img2.Picture.SaveToFile(sFileName2);
end
else
begin
Img2.Picture.Graphic := nil; //清空侧面照图像
end;
if (not Dataset.FieldByName('bAllPhoto').IsNull) then
begin
TBlobField(Dataset.FieldByName('bAllPhoto')).SaveToStream(tempstream3);
tempstream3.Position := 0;
if not Assigned(tempjpeg3) then
tempjpeg3 := TJPEGImage.Create;
tempjpeg3.LoadFromStream(tempstream3);
Img3.Picture.Bitmap.Assign(tempjpeg3);
sFileName3 := ExtractFilePath(Application.ExeName) + 'tmpAllBlob';
sFileName3 := sFileName3 + '.Jpg';
img3.Picture.SaveToFile(sFileName3);
end
else
begin
Img3.Picture.Graphic := nil; //清空全身照图像
end;
OleContainer1.Visible := False;
finally
if sFileName1 <> '' then deleteFile(sfileName1);
if sFileName2 <> '' then deleteFile(sfileName2);
if sFileName3 <> '' then deleteFile(sfileName3);
if Assigned(tempjpeg1) then
tempjpeg1.Free;
if Assigned(tempjpeg2) then
tempjpeg2.Free;
if Assigned(tempjpeg3) then
tempjpeg3.Free; tempstream1.Free;
tempstream2.Free;
tempstream3.Free;
end;
end;
end;
因此我在ClientDataSet的AfterScroll中:
procedure TFrmNew.ClientDataSet1AfterScroll(DataSet: TDataSet);
begin
Fill_Picture(DataSet);
end;但问题出来了,设置DataSetProvider 的poFetchBlobsOnDemand为True时出现了错误"Blob has not been fetched",即BLOB字段在此时是没有被取回来的,但我想在用户在DBGridEh1中移动光标定位到下一行时就取出图像,其实是不应该在ClientDataSet1AfterScroll中调用Fill_Picture 的,因为这样一旦ClientDataSet1.Open后就会执行Fill_Picture, 如果不在ClientDataSet1AfterScroll中调用Fill_Picture 请问我该如何做?谢谢了。
问题背景:在开发基于SQL Server 2000的一个传统c/S数据库应用程序时,一个用户表中有多个image(即BLOB)类型的字段(现以三个字段bFacePhoto、bSidePhoto、bAllPhoto来说明问题),用于存放三幅图(JPG格式的,已经过减肥,每幅图大小不等,最小的45KB,最大的100多KB),存取现在都是没有问题的,问题的核心是在取出相应的记录时,有相当的延时。我用的是开发工具是delphi 7,用ADO访问数据库,现在我想加入ClientDataSet和DataSetProvider,并设置DataSetProvider 的poFetchBlobsOnDemand为True,想利用这个缓冲数据集在解决读取图像时严重延时的问题,我想在列记录时先不取出BLOB信息,等用户想查看图像时,就再读取相应记录的BLob信息,我调用了Fill_Picture(DataSet)过程完成图像读取,代码如下:
procedure TFrmNew.Fill_Picture(DataSet: TDataSet);
var
sFileName1, sFileName2, sFileName3: string;
tempstream1, tempstream2, tempstream3: TStringStream;
tempjpeg1, tempjpeg2, tempjpeg3: TJPEGImage;
begin
if not DataSet.IsEmpty then
begin
try
tempstream1 := TStringStream.Create(' ');
tempstream2 := TStringStream.Create(' ');
tempstream3 := TStringStream.Create(' '); if (not Dataset.FieldByName('bFacePhoto').IsNull) then
begin
TBlobField(Dataset.FieldByName('bFacePhoto')).SaveToStream(tempstream1);
tempstream1.Position := 0;
if not Assigned(tempjpeg1) then
tempjpeg1 := TJPEGImage.Create;
tempjpeg1.LoadFromStream(tempstream1);
Img1.Picture.Bitmap.Assign(tempjpeg1);
sFileName1 := ExtractFilePath(Application.ExeName) + 'tmpFaceBlob';
sFileName1 := sFileName1 + '.Jpg';
img1.Picture.SaveToFile(sFileName1);
end
else
begin
Img1.Picture.Graphic := nil; //清空正面照图像
end;
if (not Dataset.FieldByName('bSidePhoto').IsNull) then
begin
TBlobField(Dataset.FieldByName('bSidePhoto')).SaveToStream(tempstream2);
tempstream2.Position := 0;
if not Assigned(tempjpeg2) then
tempjpeg2 := TJPEGImage.Create;
tempjpeg2.LoadFromStream(tempstream2);
Img2.Picture.Bitmap.Assign(tempjpeg2);
sFileName2 := ExtractFilePath(Application.ExeName) + 'tmpSideBlob';
sFileName2 := sFileName2 + '.Jpg';
img2.Picture.SaveToFile(sFileName2);
end
else
begin
Img2.Picture.Graphic := nil; //清空侧面照图像
end;
if (not Dataset.FieldByName('bAllPhoto').IsNull) then
begin
TBlobField(Dataset.FieldByName('bAllPhoto')).SaveToStream(tempstream3);
tempstream3.Position := 0;
if not Assigned(tempjpeg3) then
tempjpeg3 := TJPEGImage.Create;
tempjpeg3.LoadFromStream(tempstream3);
Img3.Picture.Bitmap.Assign(tempjpeg3);
sFileName3 := ExtractFilePath(Application.ExeName) + 'tmpAllBlob';
sFileName3 := sFileName3 + '.Jpg';
img3.Picture.SaveToFile(sFileName3);
end
else
begin
Img3.Picture.Graphic := nil; //清空全身照图像
end;
OleContainer1.Visible := False;
finally
if sFileName1 <> '' then deleteFile(sfileName1);
if sFileName2 <> '' then deleteFile(sfileName2);
if sFileName3 <> '' then deleteFile(sfileName3);
if Assigned(tempjpeg1) then
tempjpeg1.Free;
if Assigned(tempjpeg2) then
tempjpeg2.Free;
if Assigned(tempjpeg3) then
tempjpeg3.Free; tempstream1.Free;
tempstream2.Free;
tempstream3.Free;
end;
end;
end;
因此我在ClientDataSet的AfterScroll中:
procedure TFrmNew.ClientDataSet1AfterScroll(DataSet: TDataSet);
begin
Fill_Picture(DataSet);
end;但问题出来了,设置DataSetProvider 的poFetchBlobsOnDemand为True时出现了错误"Blob has not been fetched",即BLOB字段在此时是没有被取回来的,但我想在用户在DBGridEh1中移动光标定位到下一行时就取出图像,其实是不应该在ClientDataSet1AfterScroll中调用Fill_Picture 的,因为这样一旦ClientDataSet1.Open后就会执行Fill_Picture, 如果不在ClientDataSet1AfterScroll中调用Fill_Picture 请问我该如何做?谢谢了。
解决方案 »
- DBgrid控件,怎么能控制前两列在托动下面的滚动条的时候只动后面的,不动前两列
- 如何知道一个web地址是否可用?
- 郁闷死,好久不用DELPHI,问个最简单的问题。
- 求助:有两个Form:Form1,Fom2。Form1是自动生成的,Form2由Form1在程序运行时Create。请问该怎么做?
- 如何将类似select * from :DB.Table 加入TQuery?
- 关于电子图章中文字环形问题处理??请指点??
- 有关数据库的导入、导出的问题,请高手帮忙解决??
- DBGridEh怎样可以改变被选中的行的颜色?(可以多选行)
- 请帮助回答一个问题
- 请教一个日期转换问题
- QuickReport如何保存为pdf文件??
- memo自动折行
你在BeforeOpen、OnClose事件中写 ClientDataSet1.OnAfterScroll:=nil;在AfterOpen事件中写 ClientDataSet1.OnAfterScroll:=Fill_Picture;
BLOB型字段,另外楼主所说的 ClientDataSet1.OnAfterScroll := nil;这样不行啊,编译都通不过。
我在我的系统中存储的文件大小基本上是5MB左右的,在响应时间一般为0.3秒;如果用stringStream的话要1.1秒左右。当然,你的内存要大点才好。