Как я могу сохранить динамический массив в FileStream в Delphi?

У меня есть следующие структуры в Delphi 2009:

type
  IndiReportIndi = record
    IndiName: string;
    NameNum: integer;
    ReportIndiName: string;
  end;

var
  XRefList: array of IndiReportIndi;

где XRefList — динамический массив.

Я хочу сохранить XRefList в FileStream. Как мне это сделать И включить все строки IndiName и ReportIndiName, чтобы их можно было снова получить при последующей загрузке из этого FileStream?


person lkessler    schedule 07.12.2010    source источник
comment
С декабря 2010 г. существует новый модуль OpenSource, который стоит рассмотреть для сериализации записей или динамических массивов (с гораздо большим количеством функций, чем сериализация) — работает для Delphi 5 до XE2.   -  person Arnaud Bouchez    schedule 08.11.2011
comment
@ArnaudBouchez, ссылка не работает.   -  person SHIN JaeGuk    schedule 30.04.2021
comment
Правильная ссылка теперь blog.synopse.info/?post/2011/03/12/TDynArray-and-Record-compare/ — работает с последней версией Delphi, а также с FPC/Lazarus.   -  person Arnaud Bouchez    schedule 06.05.2021


Ответы (6)


Используйте: http://code.google.com/p/kblib/.

type
  IndiReportIndi = record
    IndiName: string;
    NameNum: integer;
    ReportIndiName: string;
  end;

  TXRefList = array of IndiReportIndi;

var
  XRefList: TXRefList;

Чтобы сохранить весь XRefList в поток, используйте:

TKBDynamic.WriteTo(lStream, XRefList, TypeInfo(TXRefList));

Чтобы загрузить его обратно:

TKBDynamic.ReadFrom(lStream, XRefList, TypeInfo(TXRefList));
person Krystian Bigaj    schedule 07.12.2010
comment
Похоже, очень хорошая рутина. Спасибо, что указали на это. - person lkessler; 08.12.2010

var
  S: TStream;
  W: TWriter;
  A: array of IndiReportIndi;
  E: IndiReportIndi;
  ...
begin
  S := nil;
  W := nil;
  try 
    S := TFileStream.Create(...);
    W := TWriter.Create(S);
    W.WriteInteger(Length(A));
    for E in A do
    begin
      W.WriteString(E.IndiName);
      W.WriteInteger(E.NameNum);
      W.WriteString(E.ReportIndiName);
    end;
  finally
    W.Free;
    S.Free
  end;
end;  

Чтобы прочитать эти данные, вы используете TReader и ReadInteger/ReadString.

person Community    schedule 07.12.2010
comment
Спасибо, ldsandon. Красиво, чисто и просто. +1. - person lkessler; 08.12.2010

Простой TFileStreamEx для сохранения переменных

http://forum.chertenok.ru/viewtopic.php?t=4642

Работаю с ними с 2005-го года, без проблем...

person TuXAPuK    schedule 11.07.2011
comment
Не знал о функции EX. Я должен изучить это. - person lkessler; 12.07.2011

Проверенное решение:

procedure TForm1.FormCreate(Sender: TObject);
VAR Stream: TFileStream;
    R: IndyRecordIndy;
begin
 Stream:= TFileStream.Create;
 TRY
   //put rec in stream
   Stream.WriteBuffer(R, SizeOf(R));

   //restore record from stram
   Stream.Position := 0;
   Stream.ReadBuffer(R, Stream.Size);
 FINALLY
  FreeAndNil(Stream);
 END;
end



;
person Z80    schedule 26.02.2013
comment
Это неправильно! Вы сохраняете указатели на строки в файле. Это бесполезные данные при следующем чтении файла. - person Tom Brunberg; 25.07.2019

Просто чтобы ответ был точным:

Попробуйте взглянуть на TDynArray обертка, способная сериализовать любую запись в бинарную, а также в/из динамических массивов.

Существует множество методов, подобных TList, включая новые методы (например, хеширование или бинарный поиск).

Очень оптимизирован для скорости и использования диска, работает с Delphi 5 до XE2 и с открытым исходным кодом.

См. также Как хранить динамические массивы в TList?

person Arnaud Bouchez    schedule 08.11.2011

person    schedule
comment
Вы могли бы использовать pointer(Result)^ вместо Result[1] в LoadString и pointer(S)^ вместо S[1] в SaveString, потому что это сохранит вызов UniqueString(). LoadString также может быть немного быстрее, если закодирован с результатом := '' во всех случаях, затем SetLength(Result,N), если N>0: поэтому не будет перераспределения памяти (с медленным перемещением), но тогда строка будет финализирована новое распределение (что быстрее). - person Arnaud Bouchez; 07.12.2010
comment
Используйте TReader/TWriter для упрощения записи стандартных типов данных. Вместо Stream.WriteBuffer(N, SizeOf(Integer)); вы бы просто написали Write.WriteInger(N) и N := Reader.ReadInteger;. У них также есть поддержка строк и вариантов, а код намного читабельнее. Вы только что продублировали код, который уже есть в Delphi. - person ; 07.12.2010
comment
@ldsandon: реализация TReader/TWriter зависит от версии Delphi и может измениться. Нежелательно полагаться на методы TReader/TWriter для реализации собственной сериализации данных. - person kludg; 07.12.2010
comment
Структура записи OP также изменится — и ваш код тоже зависит от версии Delphi. Если файл должен использоваться в приложении, скомпилированном с другой версией Delphi, необходимо добавить заголовок, содержащий информацию о версии, чтобы приложение для чтения могло использовать правильные функции чтения. - person ; 07.12.2010