代码之家  ›  专栏  ›  技术社区  ›  Alper

如何通过FireDac(Delphi)从FireBird数据库中传输zlib压缩的图像

  •  2
  • Alper  · 技术社区  · 7 年前

    实际上,我以前问过这个问题,但我删除了这个问题,因为可能我问错了,或者没有正确表达我的问题或目标。

    我们的ERP软件公司将数据库分为2个独立部分(1个用于信息,1个用于文件(图像、文件等)-文件数据库)
    问题是,文件数据库中的所有资产都是用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;
    

    谢谢

    我使用LiveBindings从数据库中获取数据,但对于压缩数据和图像处理,使用LiveBindings并不是强制性的。

    1 回复  |  直到 7 年前
        1
  •  3
  •   Victoria zac    7 年前

    您已经说过,您将只使用该数据集进行读取(不回写到DBMS),并且您的目标实际上只是解压缩获取到客户端的BLOB流。目前没有办法以某种舒适的方式(某种程度上)拦截BLOB获取

    拦截BLOB流存储的最近路径将位于 方法(它是转换获取的数据的理想场所,就在它们存储在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;