0

I would like to use SaveToStream to save a ClientDataSet ALONG WITH OTHER MATERIAL. Here is a short sample:

filename := ChangeFileExt(Application.ExeName, '.dat');
FS := TFileStream.Create(filename, fmCreate);

CDS.SaveToStream(FS);
ShowMessage('After save, position is ' + IntToStr(FS.Position));

{now write a longint}
L := 1234;
siz := SizeOf(L);
Write(L, siz);

FS.Free;

But when I try to load this back in using LoadFromStream, and I again display the position after the ClientDataSet has been loaded, I see that the position is now 4 bytes AFTER the clientdataset was originally saved. It seems that CDS.LoadFromStream just plows ahead and consumes whatever follows it. As a result, when I then try to read the longint, I get an end of file error.

It is not sufficient to just use the CDS.SaveToStream at the end of creating a file, because what I'd really like to do is to save TWO clientdatasets to the file, one after the other, plus other material.

Ideas? Thanks.

Kevin Killion
  • 123
  • 2
  • 9
  • 1
    The `ReadDataPacket` and `WriteDataPacket` methods (which are the underlying stream reader and writer methods) have the boolean parameters that allows a dataset store and read the data size to be processed to the stream. So, I think that easiest for your task might be to make a subclass for the dataset and populate (and use) this boolean parameter. – TLama Mar 21 '15 at 18:32
  • 2
    This other material will be in CAPS? – Sertac Akyuz Mar 21 '15 at 20:58

1 Answers1

0

[NB, this solution is essentially doubling up the work that (TLama's suggestion) "ReadDataPacket/WriteDataPacket" already does internally. I would use TLama's approach i.e. sub-class TClientDataSet to expose the above protected methods, and use the WriteSize parameter.]

Save the datasets to a temporary stream and then copy that to your destination stream with size information:

procedure InternalSaveToStream(AStream: TStream);
var
 ATempStream: TMemoryStream;
 ASize: Int64;
begin
 ATempStream := TMemoryStream.Create;

 // Save first dataset:
 DataSet1.SaveToStream(ATempStream, dfBinary);
 ASize := ATempStream.Size;
 AStream.WriteData(ASize);
 ATempStream.Position := 0;
 AStream.CopyFrom(ATempStream, ALength);
 ATempStream.Clear;

 // Save second dataset:
 DataSet2.SaveToStream(ATempStream, dfBinary);
 ASize := ATempStream.Size;
 AStream.WriteData(ASize);
 ATempStream.Position := 0;
 AStream.CopyFrom(ATempStream, ALength);
 ATempStream.Clear; 

 FreeAndNil(ATempStream);
end;

To read back, first read the size and then copy that section of your source to a temporary stream again and load your dataset from that:

procedure InternalLoadFromStream(AStream: TStream);
var
 ATempStream: TMemoryStream;
 ASize: Int64;
begin
 ATempStream := TMemoryStream.Create;

 // Load first datset:
 AStream.Read(ASize,SizeOf(ASize));
 ASize := ATempStream.Size;
 ATempStream.CopyFrom(AStream,ASize);
 ATempStream.Position := 0;
 DataSet1.LoadFromStream(ATempStream);

 //...etc.

end;
Phil B
  • 387
  • 5
  • 15