В Delphi используйте SaveToStream для сохранения ClientDataSets и других материалов в файл?

Я хотел бы использовать SaveToStream для сохранения ClientDataSet ВМЕСТЕ С ДРУГИМИ МАТЕРИАЛАМИ. Вот краткий пример:

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;

Но когда я пытаюсь загрузить это обратно с помощью LoadFromStream и снова отображаю позицию после загрузки ClientDataSet, я вижу, что позиция теперь составляет 4 байта ПОСЛЕ того, как клиентский набор данных был первоначально сохранен. Кажется, что CDS.LoadFromStream просто идет вперед и потребляет все, что следует за ним. В результате, когда я затем пытаюсь прочитать longint, я получаю ошибку конца файла.

Недостаточно просто использовать CDS.SaveToStream в конце создания файла, потому что мне действительно хотелось бы сохранить в файл ДВА клиентских набора данных, один за другим, плюс другой материал.

Идеи? Спасибо.


person Kevin Killion    schedule 21.03.2015    source источник
comment
Методы ReadDataPacket и WriteDataPacket (которые являются базовыми методами чтения и записи потока) имеют логические параметры, которые позволяют хранить набор данных и считывать размер данных для обработки в поток. Итак, я думаю, что самой простой задачей для вашей задачи может быть создание подкласса для набора данных и заполнение (и использование) этого логического параметра.   -  person TLama    schedule 21.03.2015
comment
Этот другой материал будет в CAPS?   -  person Sertac Akyuz    schedule 21.03.2015


Ответы (1)


[Обратите внимание: это решение, по сути, удваивает работу, которую (предложение TLama) «ReadDataPacket/WriteDataPacket» уже выполняет внутри. Я бы использовал подход TLama, т. е. подкласс TClientDataSet, чтобы раскрыть вышеупомянутые защищенные методы и использовать параметр WriteSize.]

Сохраните наборы данных во временный поток, а затем скопируйте их в целевой поток с информацией о размере:

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;

Чтобы прочитать обратно, сначала прочитайте размер, а затем снова скопируйте этот раздел вашего источника во временный поток и загрузите свой набор данных из него:

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;
person Phil B    schedule 05.10.2016