Concatenate TStringStream

2019-09-02 16:18发布

问题:

I would like to concatenate some TStringStreams into one Stream.

I have some blob (varbinary(max)) fields in SQL Server and and I want to create a stream from all the rows then save it to a file.

var
  // MSWord: Variant;
  i: Int32;
  sA: TStringStream;
  sP: TStringStream;
  s: TStringStream;
  // fString: TStrings;
begin
  sA := TStringStream.Create;
  s := TStringStream.Create;
  sP := TStringStream.Create;
  try
    with DateED do
    begin
      BlobField.SaveToStream(sA);
      sA.SaveToStream(s);
      // s.CopyFrom(sA, sA.Size);
      // s.LoadFromStream(sA);
      s.Position := sA.Size;
    end;
    with DateED.spED_TemplateParagraf do
    begin
      First;
      while not EOF do
      begin
        DateED.BlobField.SaveToStream(sP);
        sP.SaveToStream(s);
        s.Position := sP.Size;
        sP.Clear;
        Next;
      end;
    end;
    s.SaveToFile('D:\test.doc');
  finally
    sA.Free;
    s.Free;
    sP.Free;
  end;

For some reason this does not do the trick, anyone can help me with a suggestion? How can I concat my Blob fields?

EDIT :

So after trying David's solution

   procedure CopyBlobFieldToStream(ds: TDataSet; field: TBlobField; outputStream: TStream);
    var
      inputStream: TStream;
    begin
      inputStream := ds.CreateBlobStream(field, bmRead);
      try
        outputStream.CopyFrom(inputStream, inputStream.Size);
      finally
        inputStream.Free;
      end;
    end;

    ....

    stream := TFileStream.Create(fileName, fmCreate);
    try
      CopyBlobFieldToStream(ds, field1, stream);
      CopyBlobFieldToStream(ds, field2, stream);
    finally
      stream.Free;
    end;

I still can't find all the info from the fields into

var
  i: Int32;
  stream: TFileStream;
  Path1: string;
  WordApp: TWordApplication;
begin
  Path1 := IncludeTrailingPathDelimiter(GetEnvironmentVariable('TEMP')) +
    FormatDateTime('yyyymmddhhnnssz', Now) + '.doc';
  WordApp := TWordApplication.Create(nil);
  stream := TFileStream.Create(Path1, fmCreate);
  try
    try
      with dm do
      begin
        DataSet.First;
        CopyBlobFieldToStream(dm.DataSet,
          dm.DataSetBlobField, stream);
        ShowMessage(IntToStr(stream.Size));
        DataSet.Next;
        CopyBlobFieldToStream(dm.DataSet,
          dm.DataSetBlobField, stream);
        ShowMessage(IntToStr(stream.Size));
        CopyBlobFieldToStream(dm.DataSet2,
          dm.DataSet2BlobField, stream);
        ShowMessage(IntToStr(stream.Size));
      end;
    finally
      stream.Free;
    end;
    WordApp.Documents.Open(Path1, EmptyParam, False, EmptyParam, EmptyParam,
      EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam,
      EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam);
    WordApp.Visible := True;
  finally
    WordApp.Free;
  end;

This is the way I call, but in the Word dock I only find the text from the first blob field but indeed the stream size is increasing.

回答1:

A string stream is the wrong tool for the job. You don't have text, you have binary data. You are simply looking to concatenate two binary BLOBs. Do that with code something along these lines:

procedure ConcatenateBlobField(ds: TDataSet; field1, field2: TBlobField; outputStream: TStream);
var
  inputStream: TStream;
begin
  inputStream := ds.CreateBlobStream(field1, bmRead);
  try
    outputStream.CopyFrom(inputStream, inputStream.Size);
  finally
    inputStream.Free;
  end;

  inputStream := ds.CreateBlobStream(field2, bmRead);
  try
    outputStream.CopyFrom(inputStream, inputStream.Size);
  finally
    inputStream.Free;
  end;
end;

In order to save to a file, create a TFileStream and pass it to the function.

stream := TFileStream.Create(fileName, fmCreate);
try
  ConcatenateBlobFields(ds, field1, field2, stream);
finally
  stream.Free;
end;

Or perhaps like this:

procedure CopyBlobFieldToStream(ds: TDataSet; field: TBlobField; outputStream: TStream);
var
  inputStream: TStream;
begin
  inputStream := ds.CreateBlobStream(field, bmRead);
  try
    outputStream.CopyFrom(inputStream, inputStream.Size);
  finally
    inputStream.Free;
  end;
end;

....

stream := TFileStream.Create(fileName, fmCreate);
try
  CopyBlobFieldToStream(ds, field1, stream);
  CopyBlobFieldToStream(ds, field2, stream);
finally
  stream.Free;
end;