Как хранить объект к диску?

Как хранить объект к диску во всей его славе? Мой объект получен из TObjectList, таким образом, он содержит другие объекты.

Который является самым быстрым и самым легким путем? Который является совместимым путем?

Сериализация НЕ ЯВЛЯЕТСЯ решением, так как я хочу сохранить также непубличные свойства и список объектов, которые это содержит!

В настоящий момент я пытающийся сохранить каждый объект независимо как двоичный файл, которые затем упаковываются вместе. Это - долгий процесс, но позволяет мне загружать старые версии объекта с более новой версией программы (совместимость с предыдущими сохраненными проектами). Так или иначе сложность начала расти, и это не выглядит хорошим больше.

14
задан WeGoToMars 28 February 2010 в 20:07
поделиться

7 ответов

Я также в основном использую ручную сериализацию для своих собственных структур данных. Многовариантность версий - одна из основных причин.

Однако в вашем случае это сложно, поскольку не все ваши объекты (tobjectlist) являются производными от собственной иерархии, содержащей виртуальные абстрактные методы для загрузки / хранения.

Сериализация D2010 (которая afaik позволяет RTTI почти все) могла бы быть решением, но, вероятно, потребует новую версию delphi, и, что еще хуже, это означает конец ручному управлению версиями. (например, копирование значений из старых полей в новые при изменении формата)

Если ручная потоковая передача выходит из-под контроля, другой подход может заключаться в наличии абстрактных определений для части данных ваших объектов и генерации исходного кода ( объявления полей и потоковый код) из этих абстрактных определений. Преимущество состоит в том, что вы можете вставлять какой-то собственный код здесь и там, когда вам нужно, или исправлять свой генератор для устранения проблем с версией.

Я сделал это один раз для отображения бизнес-объекта в SQL с более чем 800 объектами. Так как это было время до появления дженериков в Delphi, я создал типизированный контейнерный тип для каждого объекта, а также для других вспомогательных и конвертирующих объектов / подпрограмм.

Это большая работа по настройке, и она того стоит, только если у вас есть проект с действительно большим количеством объектов и полей (сотни, если не тысячи) и вы уверены, что вам нужно будет поддерживать его со значительными изменениями. на довольно долгое время.

2
ответ дан 1 December 2019 в 15:01
поделиться

Если вы используете Delphi 2010, все будет намного проще благодаря новому модулю RTTI, Роберт Лав написал хороший модуль для сериализации объектов в XML называется XMLSerial .

Вы можете прочитать об этом в его блоге: Сериализация XML - базовое использование

4
ответ дан 1 December 2019 в 15:01
поделиться

Думаю, для этого существует множество способов, в прошлом я использовал для этой цели inifiles, полезный, поскольку TMemInifile позволяет вам делать много хрюкать в памяти перед сохранением на диск. Поскольку у вас есть иерархия, которую нужно сохранить, вы можете рассмотреть возможность использования чего-то вроде XML, но я лично этого не делал, поэтому не могу посоветовать по этому поводу.

0
ответ дан 1 December 2019 в 15:01
поделиться

Вам нужно придумать способ кодирования этого объекта как строки, чтобы при создании нового объекта с этой строкой вы получали тот же объект. Это называется сериализацией, и некоторые языки предоставляют вам эту функцию.

Например, если у вас есть этот объект:

class serialize_me {
 private:
   int a;
   float b;
 public:
   double c;
}

и a = 5, b = 3,2 и c = 67,5

, ваша строка может выглядеть так:

a5b3.2c67.5

Тогда вы может проанализировать эту строку и присвоить соответствующие значения всем членам.

Я думаю, само собой разумеется, что строки легко хранить на диске.

РЕДАКТИРОВАТЬ: Это очень простой пример, но я думаю, вы можете достаточно легко понять концепцию.

РЕДАКТИРОВАТЬ: Сериализация, специфичная для Delphi . Внизу страницы есть ссылка на полноценный класс XML-сериализатора.

0
ответ дан 1 December 2019 в 15:01
поделиться

Если объект является производным от TPersistent, сериализацию XML или JSON легко выполнить с помощью библиотек с открытым исходным кодом:

Одним из способов упростить управление версиями является уровень защиты от коррупции между моделью предметной области и уровнем сохраняемости. (возможно, с использованием объектов передачи данных, которые не будут меняться при каждом изменении модели предметной области).

Для автоматического управления версиями см. Эту статью: Перенос сериализованных объектов Java с помощью XStream и XMT

XMT представляет класс VersionedDocument для создания версий сериализованных XML-файлов и обработки миграции. Такой же дизайн можно легко реализовать с помощью Delphi.

0
ответ дан 1 December 2019 в 15:01
поделиться

Вы утверждаете, что сериализация не является решением, но я спрашиваю, почему нет? Я уже делал нечто подобное в прошлом, но вот что я сделал.

Я создал класс компонента, который не делал ничего, кроме сериализации объекта, основанного не на TPersistant, чтобы я мог передавать его в потоковом режиме, используя возможности потоковой передачи VCL.

Например:

//Прошу простить меня за возможные ошибки, так как я пытаюсь напечатать это от балды. Также, это не будет функционально полным.

unit streamlist1;

interface

uses MyListObjectUnit;

procedure SaveList(fielname:string; data:TMyListObject);
procedure LoadList(filename:string; var data:TMyListObject);

implementation

type
  TMyListStreamer = class(TComponent)
  private
    fMyList : TMyListObject;
    procedure ReadList(Reader:TReader); //This is where the magic happens
    procedure WriteList(Writer: TWriter); //This is where the magic happens (x2)
  public
    procedure DefineProperties(Filer: TFiler); override; //defined in TPersistent
    procedure AssignMyList(data:TMyListObject);
    procedure PopulateData(var data:TMyListObject);
  end;


TMyListStreamer.procedure DefineProperties(Filer: TFiler); override; //defined in TPersistent
begin
  Filer.DefineProperty('MyObjList', ReadList, WriteList, true);
  //Filer.DefineBinaryProperty('MyObjList', ReadList, WriteList, true); //your choice
end;

procedure TMyListStreamer.ReadList(Reader:TReader); //This is where the magic happens
begin
  //Use the reader class to read in anything you want...
end;

procedure TMyListStreamer.WriteList(Writer: TWriter); //This is where the magic happens (x2)
begin
  //Use the writer class to write out anything you want...
end;

procedure SaveList(fielname:string; data:TMyListObject);
var
  wFile : TFileStream;
  wList : TMyListStreamer;
begin
  RegisterClass(TMyListStreamer);
  Try
    wFile := TFileStream.Create(filename, fmcreate);
    wList := TMyListStreamer.create(nil);
    try
      wList.AssignMyList(Data);
      wFile.WriteComponent(wList);
    finally
      wFile.Free;
      wList.free;
    end;
  finally
    Unregisterclass(TMyListStreamer);
  end;
end;

procedure LoadList(filename:string; var data:TMyListObject);
var
  wFile : TFileStream;
  wList : TMyListStreamer;
begin
  RegisterClass(TMyListStreamer);
  Try
    wFile := TFileStream.Create(filename, fmOpenRead);
    try
      wList := TMyListStreamer(wFile.ReadComponent(Nil));

      if assigned(data) and assigned(wList) then
        wList.PopulateData(data);

      if assigned(wList) then
        wList.free; 
    finally
      wFile.Free;
    end;
  finally
    Unregisterclass(TMyListStreamer);
  end;
end;

Используя этот метод, вы можете передавать (сериализовать) что угодно из VCL или пользовательских данных. Это займет немного времени для настройки, но преимущество в том, что вы можете контролировать все, что входит и выходит из файла данных. Вы даже можете, немного подумав, создать флаг версии и обрабатывать различные данные, игнорируя или изменяя определенные данные в новых версиях программы/компонента.

Вы даже можете передавать данные других объектов VCL из вашего потокового компонента, если вы уже знаете тип объекта (т.е. объекты на основе TComponent/TPersistant), используя существующие методы TReader/TWriter.

Это не полное решение, но оно должно привести вас туда, куда вы хотите, если вы немного поработаете.

2
ответ дан 1 December 2019 в 15:01
поделиться

Ваше текущее решение, вероятно, лучшее, если вы собираетесь иметь отдельные версии объекта на протяжении многих лет .

Что я делаю, так это создаю методы SaveToStream () и LoadFromStream () и вручную записываю свойства объекта в tstream в фиксированном порядке, добавляя к нему префикс с номером версии структуры. Преимущество этого, как вы упомянули, заключается в том, что вы можете лучше адаптироваться к более старым версиям потока. Например, если у вас 5 версий, но вам нужно что-то инициализировать определенным образом для файлов версии 3, это легко сделать. Затем вы оборачиваете его функцией SaveToFile (), которая создает TFileStream и вызывает SaveToStream ().

Я считаю, что существует класс TWriter, который позволяет вам легче записывать различные типы данных в поток ... или вы можете достаточно просто создать свои собственные. (Я сделал свой собственный потомок файлового потока, чтобы справиться с этим)

Если вы сохраняете несколько объектов в один поток, вы можете захотеть отметить позицию перед записью каждого объекта, а затем вернуться и отметить длину, чтобы вы (или кто-либо, имеющий доступ к файлам) может пропустить файл, не читая его.

Кроме того, если у вас есть иерархия классов, которые вы хотите сохранить, «загрузите снизу» предшествующий класс со всеми свойствами, которые вы хотите сохранить в файл. Таким образом, вам понадобится только одна реализация процедуры сохранения. Это немного менее эффективно, поскольку вы переносите переменные, которые вам не обязательно нужны во всех объектах, но им гораздо проще управлять.

2
ответ дан 1 December 2019 в 15:01
поделиться
Другие вопросы по тегам:

Похожие вопросы: