实际上,我之前已经问过这个问题,但我删除了这个问题,因为可能是我说错了或没有正确表达我的问题或目标。
我正在连接到我们的ERP软件数据库(FireBird v2.1)以检索用于导出为XML的数据。但与此同时,我需要将所有产品图像保存到单独的文件夹中(我将汇总所有数据和图像,然后上传到Web服务器以导入电子商务应用程序)。
我们的ERP软件公司将数据库分为两个独立的部分(1个用于信息,1个用于文件(图像,文件等) - 文件数据库)
问题是,FILES数据库中的所有资产都用zlib压缩,所以我不能直接通过LiveBindings传输这些图像(LinkPropertyToFieldBitmap中的eval错误:加载位图失败)我知道这是正常的,因为文件是压缩的并插入为BLOB。
我需要将这些zlib压缩数据作为流来使用它作为解压缩过程的输入。
我打算使用以下程序将解压缩的图像保存为文件。
procedure TForm1.DecompressStream(Stream: TStream);
var
LOutput: TFileStream;
LUnZip: TZDecompressionStream;
begin
Stream := TStream.Create();
{ Create the Output and Decompressed streams. }
LOutput := TFileStream.Create('SKU OF PRODUCT.jpg', fmCreate);
LUnZip := TZDecompressionStream.Create(Stream);
{ Decompress data. }
LOutput.CopyFrom(LUnZip, 0);
{ Free the streams. }
Stream.Free;
LUnZip.Free;
LOutput.Free;
end;
注意:也许上面的过程不是正确的但是在能够以流的形式获取zlib数据之后我可以调试以纠正它。 感谢..
更新:我正在使用LiveBindings从数据库中获取数据,但使用LiveBindings对于压缩数据和图像处理不是必需的。
答案 0 :(得分:2)
您已经说过,您将仅使用该数据集进行读取(没有写回DBMS),并且您的目标实际上只是解压缩到客户端的BLOB流。目前无法以某种舒适的方式拦截BLOB抓取( OnBlobFetching 事件的种类)。
拦截BLOB流存储的最近路径是在 TFDDatSRow.InternalSetData 方法中(它是转换所获取数据的理想位置,就在它们存储在FireDAC的内部数据存储之前)。但这需要修改源代码。
如果没有源代码修改,您可以编写例如AfterGetRecord事件的事件处理程序,并从那里解压缩流。如果您决定直接在字段中覆盖已获取的流(理想情况下将数据集设置为只读模式),请务必小心不要将修改后的数据更改提交到数据库中。
一个例子:
procedure TForm1.FDQuery1AfterGetRecord(DataSet: TFDDataSet);
var
BlobStream: TFDBlobStream;
HelpStream: TMemoryStream;
begin
{ create BLOB stream for reading and writing }
BlobStream := DataSet.CreateBlobStream(DataSet.FieldByName('Data'), bmReadWrite) as TFDBlobStream;
try
{ create intermediate stream }
HelpStream := TMemoryStream.Create;
try
{ decompress BLOB stream into helper one }
ZDecompressStream(BlobStream, HelpStream);
{ and overwrite the original BLOB stream content with uncompressed data; note, that
TFDBlobStream must know about the modification, otherwise it won't store the data
into the storage when this stream is released (LoadFromStream won't work here) }
BlobStream.Clear;
BlobStream.Write(HelpStream.Memory^, HelpStream.Size);
finally
HelpStream.Free;
end;
finally
BlobStream.Free;
end;
end;
或类似地在较低级别:
procedure TForm1.FDQuery1AfterGetRecord(DataSet: TFDDataSet);
var
DataRow: TFDDatSRow;
DataCol: TFDDatSColumn;
InLength: LongWord;
InBuffer: Pointer;
OutLength: Integer;
OutBuffer: Pointer;
begin
{ get the current row storage object }
DataRow := DataSet.GetRow;
{ for column indexing in following calls find column by name }
DataCol := DataSet.Table.Columns.ColumnByName('Data');
{ try to get pointer to the raw data buffer for the column with given index }
if DataRow.GetData(DataCol.Index, rvDefault, InBuffer, 0, InLength, False) then
begin
{ decompress the data buffer into another allocated by this procedure }
ZDecompress(InBuffer, InLength, OutBuffer, OutLength);
try
{ start editing this storage row }
DataRow.BeginEdit;
try
{ let the storage copy the decompressed data from the buffer }
DataRow.SetData(DataCol.Index, OutBuffer, OutLength);
finally
{ finish this storage row editing without creating new row version, so the engine
won't take the data modification as update }
DataRow.EndEdit(True);
end;
finally
{ and release the buffer allocated by ZLib library function call, input buffer used
here belongs to FireDAC's storage }
FreeMem(OutBuffer);
end;
end;
end;