Этот пост содержит основные определения серии.
Сериализация
Операция записи каких-то данных в файл заключается в их сериализации (от англ. serialize - переводить в последовательную форму) в последовательность байт (и записи результата в файл).Обратной к операции сериализации является операция десериализации — восстановление начального состояния структуры данных из байтовой последовательности.
Эта байтовая последовательность записывается или загружается в/из файл(а). Соответственно, сериализация используется для передачи объектов по сети и для сохранения их в файлы. Это просто название для операции "выкладывания" ("упаковки") данных в файл. Десериализация - операция "распаковки" данных из файла. Если вы сериализуете какие-то данные, а затем десериализуете их, то получите эквивалентный набор данных, имеющих тот же смысл, что и оригинал. При некоторых дополнительных условиях это будет полная копия оригинала.
Любой из схем сериализации присуще то, что кодирование данных последовательно по определению, и извлечение любой части сериализованной структуры данных требует, чтобы весь объект был считан от начала до конца и воссоздан. Во многих приложениях такая линейность полезна, потому что позволяет использовать простые интерфейсы ввода/вывода общего назначения для сохранения и передачи состояния объекта.
Маршалинг
Почти синонимом термина "сериализация" является маршалинг (от англ. marshal — упорядочивать). Обратный процесс - демаршалинг (аналог десериализации). Маршалинг - более общее понятие, чем сериализация. Всякая сериализация является частным случаем маршалинга. Отличие маршалинга от сериализации в том, что сериализация предполагает упаковку лишь данных программы. Скажем, матрицы чисел, записи о сотруднике в картотеке или таблицы высот игрового уровня. Когда говорят про маршалинг, подразумевают сериализацию не только данных программы, но и её программного состояния, мета-информации. К примеру, сериализация объекта с полями запишет лишь данные объекта (поля). Маршалинг же объекта запишет не только информацию о его данных (полях), но и информацию по восстановлению структуры объекта - класс объекта, либо же его мета-информацию для реконструирования типа.Маршалируя и демаршалируя объект вы создаёте его полную копию. При этом принимающая сторона может ничего не знать про объект.
Маршалинг используется в различных механизмах RPC, где есть необходимость в передаче данных между процессами и потоками, а также для обмена данными с движками скриптов. Во всех этих случаях маршалинг используется, чтобы "упаковать" вызов метода, его параметры, передать сообщение на другую сторону для выполнения (другой процесс или машину в случае RPC или скрипт в случае скриптового движка), и провести обратный процесс (демаршалинг) для распаковки ответа в результат вызова метода.
Персистентность
Персистентность - это свойство чего-либо поддерживать постоянное (перманентное) состояние. Скажем, применительно к объекту персистентность обычно означает способность этого объекта сериализовать (и десериализовать) самого себя.Способы сериализации данных в Delphi
В любом случае, если вы мало что поняли из сказанного выше, вам нужно вынести только одну вещь: "сохранение данных в файл - это сериализация данных в файл, загрузка данных из файла - это десериализация".Итак, для наших целей в качестве примеров мы будем рассматривать загрузку и сохранение таких данных:
- Строка или набор строк - текстовые данные
- Массив чисел:
array of Extended
- набор однородных данных - Пары имя-значение - набор ассоциативных данных
- Запись - набор неоднородных данных
- Набор (массив) из записей - иерархический набор данных
- Массив из записей внутри записи - составные данные
- Какие-то другие примеры данных, иллюстрирующие особенности конкретных подходов
- Одно значение:
Double
- Одно значение переменного размера:
String
- Набор однородных значений:
array of Double
- Набор однородных значений переменного размера:
array of String
- Запись - набор неоднородных данных:
type TData = record Signature: LongWord; Size: LongInt; Comment: String; CRC: LongWord; end;
- Набор (массив) из записей - иерархический набор данных:
type TPerson = record Name: String; Age: Integer; Salary: Currency; end; TPersons = array of TPerson;
- Массив из записей внутри записи - составные данные:
type TCompose = record Signature: LongInt; Person: TPerson; Count: Integer; Related: TPersons; end; TComposes = array of TCompose;
- Какие-то другие примеры данных, иллюстрирующие особенности конкретных подходов
Я, быть может, не очень по теме, но вопрос такой: как вы думаете, что происходит с аргументами сеттером после десериализации?
ОтветитьУдалитьproperty Coll: TCollection read GetCollection write SetCollection;
...
procedure SetCollection(const Value: TCollection)
begin
// тут используется копирование коллекции из аргумента в поле по типу:
Value.CloneTo(FColl);
end;
Известно, что некомпоненты наследники TPersistent при десериализации вообще обходят сеттеры - они десерилизуются сразу в значения полей объекта (это можно проследить на примере TStringList - вы никогда не попадёте в SetStringList при десериализации). Например, такой класс:
TOrigin = class(TPersistent)
private
FX: Integer;
FY: Integer;
FZ: Integer;
procedure SetX(const Value: Integer);
procedure SetY(const Value: Integer);
procedure SetZ(const Value: Integer);
published
property X: Integer read FX write SetX;
property X: Integer read FY write SetY;
property X: Integer read FZ write SetZ;
если будет являться свойством другого класса:
TSome = class(TComponent)
private
FOrigin: TOrigin;
procedure SetOrigin(const Value: TOrigin);
published
property Origin: TOrigin read FOrigin write SetOrigin;
то при десериализации TSome мы никогда не попадём в SetOrigin, значения X, Y и Z будут вписаны напрямую в Origin.X, Origin.Y и Origin.Z именно поля TSome, полученного через геттер.
Теперь собственно вопрос: а что происходит потом с этими Value, после десериализации? Надо ли очищать память (Value.Free) вручную или это предусмотрено языком?
Например, в случае с TOrigin - не надо, мы попросту не попадаем в сеттер -> никакого лишнего объекта нет. А что делать, если всё происходит именно через сеттер, но объект не замещается в поле класса, а клонируется (по типу коллекции)? Надо ли его очистить и станет ли он утечкой, если этого не сделать?
Не уверен, что понял проблему.
Удалить> некомпоненты наследники TPersistent при десериализации вообще обходят сеттеры
Неверно. Вот стек вызова для вашего TSome/TOrigin:
Unit1.TOrigin.SetX(5)
SetOrdProp
TReader.ReadProperty
TReader.ReadDataInner
TReader.ReadData
TComponent.ReadState
TStream.ReadComponent
Unit1.Button1Click
> это можно проследить на примере TStringList - вы никогда не попадёте в SetStringList при десериализации
Вообще-то у TStringList (вернее - его предка TStrings) нет published свойств. Вместо этого TStrings переопределяет DefineProperties, где указывает, что ему нужно сохранять свойство Strings, и что делать это он будет через ReadData и WriteData.
> то при десериализации TSome мы никогда не попадём в SetOrigin, значения X, Y и Z будут вписаны напрямую в Origin.X, Origin.Y и Origin.Z именно поля TSome, полученного через геттер
Разумеется, ведь вы читаете свойства объекта, а не объект. Поэтому SetOrigin вызван не будет, но будут вызваны SetX и т.д.
> а что происходит потом с этими Value, после десериализации?
Как уже должно быть понятно к этому моменту - нет никаких Value во время десериализации. RTL просто читает свойства объекта из потока.