| | | | |
Упрощаем работу с потоками (TStream) | Полный текст материала
Другие публикации автора: Юрий Спектор
Цитата или краткий комментарий: «... В Delphi введен механизм потокового ввода-вывода, значительно упрощающий наш нелегкий труд. Однако структура данных может быть достаточно сложна. К тому же, в разных проектах она наверняка будет различна. Все это заставляет нас снова и снова писать сотни строчек однообразного кода записи/чтения данных. ...» |
Важно:- Страница предназначена для обсуждения материала, его содержания, полезности, соответствия действительности и так далее. Смысл не в разборке, а в приближении к истине :о) и пользе для всех.
- Любые другие сообщения или вопросы, а так же личные эмоции в адрес авторов и полемика, не относящаяся к теме обсуждаемого материала, будут удаляться без предупреждения авторов, дабы не мешать жителям нормально общаться.
- При голосовании учитывайте уровень, на который расчитан материал. "Интересность и полезность" имеет смысл оценивать относительно того, кому именно предназначался материал.
- Размер одного сообщений не должен превышать 5К. Если Вам нужно сказать больше, сделайте это за два раза. Или, что в данной ситуации правильнее, напишите свою статью.
Всегда легче осудить сделанное, нежели сделать самому. Поэтому, пожалуйста, соблюдайте правила Королевства и уважайте друг друга.
Добавить свое мнение.
| | Содержит полезные и(или) интересные сведения | [1] | 6 | 85.7% | | | | Ничего особенно нового и интересного | [2] | 1 | 14.3% | | | | Написано неверно (обязательно укажите почему) | [3] | 0 | 0% | | Всего проголосовали: 7 | | | Все понятно, материал читается легко | [1] | 8 | 100% | | | | Есть неясности в изложении | [2] | 0 | 0% | | | | Непонятно написано, трудно читается | [3] | 0 | 0% | | Всего проголосовали: 8 |
[TStream] [Работа с потоками (TStream)] [RTTI] [Интерфейсы]
Отслеживать это обсуждение
Всего сообщений: 1520-06-2007 03:14сообщение от автора материала может для простых классов оно и не надо, но упускается возможность создания свойств которые не должны записываться Stored false
Да, можно и такое предусмотреть. Совершенно несложно. Сделать проверочку на IsStoredProp. |
|
19-06-2007 23:47извиняюсь за уточнение
может для простых классов оно и не надо, но упускается возможность создания свойств которые не должны записываться
Stored false
а их использование удобно для инспектора объектов
например, часто делаю такую вещь
x1 - первая координата
x2 - вторая координата
dx= x2-x1 - разница между ними
пользователь может выбрать что ему вводить x2 или dx
но это наверное можно решить допустим через флаг пропуска
для версионности всё же придётся пользоваться именами |
|
07-04-2006 08:53Маленькое замечание:
Описанный способ игнорирует
некоторые полезные классы, например TStrings,
которые записывают свои данные через
DefineProperties/DefineBinaryProperties. Сообщение не подписано |
|
05-04-2006 23:46сообщение от автора материала Я только не понял зачем наследование от TRttiObject.
Вызвав метод SaveToStream все свойства будут записаны в поток, никакого кода больше писать не надо. Собственно этому статья и посвящена.
И с каких это пор TGraphic и другие объекты VCL поддерживают интерфейс IStreamPersist?
TGraphic = class(TInterfacedPersistent, IStreamPersist)
По поводу сохранения более легких чем Tcomponent объектов.
А почему вы приводите код сохранения в поток компонента? |
|
05-04-2006 21:09Я только не понял зачем наследование от TRttiObject.
Чтобы ограничить что можно писать в поток? Или для красоты?
И с каких это пор TGraphic и другие объекты VCL поддерживают интерфейс IStreamPersist?
Это извращение можно просто реализовать в виде функции
CoolSaveToStream(Object: TPersistent; Stream: TStream); overload;
CoolSaveToStream(Objects:array of TPersistent; Stream: TStream); overload;
И по поводу WriteClassProp. Если ваш объект не дерево, а сеть (т.е. содержат повторяющиеся ссылки на один и тот же объект), то этот код не прочитает корректно объект из потока. Надо запоминать, какие объекты уже сброшены в поток и при повторе записывать ссылку, а не свойства.
По поводу сохранения более легких чем Tcomponent объектов.
В любом случае чем возиться с M+ лучше ограничиться наследниками TPersistent (на то и название).
TEnvelope = class(TComponent)
fPersistent: TPersistent;
published
property Body: TPersistent read fPersistent write fPersistent;
end;
CoolSaveToStream(Object: TPersistent; Stream: TStream);
var E: TEnvelope;
begin
if Object is TComponent then
Stream.WriteComponent(TComponent(Object))
else if Object is TPersistent then
begin
E := TEnvelope.Create(nil);
try
E.Body := Object;
Stream.WriteComponent(E);
finally E.Free; end;
end;
end;
Надеюсь читатель сами сможете написать. |
|
01-04-2006 05:38Ins
Тут всё не так просто: если будем генерить исключение, то это ничем не лучше чем тупо читать несмотря ни на что. Хочется, чтобы старые файлы читались без проблем на новых версиях. Оставлять заботу о версиях на программисте, не самое лучшее решение, автоматический контроль надёжнее. Думаю простыми средствами это не решить, к примеру Borland с каждым свойством сохраняет его тип и даже перечислимые с множествами в текст переводит, что бы у нас было меньше проблем.
Я просто подумал о применимости данного модуля: для временного хранения информации в пределах версии (ну по сети например передавать между клиентом и сервером) - хорошо подходит (просто, компактно), для хранения документов или конфигов - очень плохо (абсолютно не переносим с версии на версию). Плюсы над стандартным сериализатором имеются только при сохранении большого количества однотипных объектов. Так может стоит (за счёт усложнения конечно) взять лучшее от обоих вариантов и сделать нечто позволяющее быстро работать с большими массивами объектов, но не имеющее проблем с версиями. Я это вижу как разделение метаинформации (информации о свойствах и типах) и собственно данных (значений свойств). То есть мы фактически должны сохранить часть RTTI информации в файл и при последующем чтении сравнивать её с тем что есть в EXE-шнике, все отличия лучше всего пропускать через специальный интерфейс который будет решать, что делать с этим свойством (чего очень не хватает в TReader-е, он просто генерит исключение на неизвестных свойствах). Так как это сравнение можно произвести всего один раз для данной версии файла, то разбор должен быть очень быстр, мы фактически пройдёмся по сгенерированному на этапе парсинга метаинформации массиву из PPropInfo (и указателей на функции для сложных свойств, которые в стандартном сериализаторе объявляются через DefineProperties) и подряд считаем свойства из потока. Никаких поисков свойств в таблицах (и строковых значений для перечислимых), никакой информации о типе итд, только данные, одно за другим.
В идеале это должно быть совместимо со стандартным механизмом (что бы формочки например сохранять).
А кто ни будь знает как с этим делом в .NET дела обстоят? Желательно ссылку хорошую на детальное описание сериализации в .NET. |
|
31-03-2006 09:26сообщение от автора материала DRON:
Спасибо за совет. Как Вы считаете следующий метод подойдет?
TRttiObject = class(TInterfacedPersistent, IStreamPersist)
protected
class function ClassSignature: String; virtual;
public
...
end;
class function TRttiObject.ClassSignature: String;
begin
Result:='';
end;
При записи класса вначале записывается результат функции ClassSignature. При чтении, считываемое значение сравнивается с ClassSinature, в случае совпадения данные считываются дальше, иначе возбуждается исключение. Но в этом случае программист должен при внесении изменений, изменить и результат функции ClassSignature, например если раньше он был 'MySign v1.0', сделать например 'MySign v1.1'. |
|
30-03-2006 13:28И используют метод потока ReadComponent который все написанное в статье и реализует и даже больше.
Больше я так понимаю относится к размеру получаемого файла? Стандартная сериализация конечно хорошая вещь, но при сохранении тысяч простых объектов, там пишется слишком много служебной информации.
To Ins:
Неплохо было бы добавить хоть какой-то контроль версий, а то замучаешься конвертеры из старых в новые версии писать: добавил поле и старые файлы уже не читаются. Может стоит сделать как в TReader/Writer-е: сохранять имена свойств, но делать это не в каждом объекте, а один раз в начале файла, тогда и гибкость будет и компактность.
Кто бы написал аналогичную сериализацию для record-ов... |
|
30-03-2006 06:21Собственно обычно работают с TComponent и его наследниками.
И используют метод потока ReadComponent который все написанное в статье и реализует и даже больше. При необходимости более гибкой работы используют TReader и TWrite. Собственно статья прилогатся http://www.rsdn.ru/article/delphi/serialization.xml |
|
30-03-2006 03:46Полезная вещь.
Действительно, бывает надобность писать в поток простые классы, это дает возможность делать программы с "объектным" сохранением данных, и готовый пример в этом случае - большая помощь. |
|
29-03-2006 06:54Для panda
Описанный здесь способ, лучше того о котором Вы говорите тем, что он может быть применен к простейшим классам, которые не обязательно должны быть наследниками TComponent.
Кроме того, статья интересна тем, что дает механизм работы с информациях о типах свойств класса в run-time. Это может быть полезно для тех, кто пытается делать редакторы свойств, подобные Object Inspector и является хорошим дополнением к статье http://www.delphikingdom.com/asp/viewitem.asp?catalogid=565 |
|
28-03-2006 02:01Мне этот материал может в будущем пригодится. Часто бывают такие ситуации когда надо сохранять в поток не TComponent и тогда указаная методика может пригодится. Я знал что так можно сделать, но потратил бы не мало времени на написание самостоятельно. Очень удобно иметь возможность взглянуть на готовый пример. |
|
28-03-2006 00:37сообщение от автора материала Panda:
Принципиально - ничем, разве что экономичнее, скажем так, это альтернатива. Я выложил этот материал, потому что сам им пользуюсь, и не только потому, что свое всегда приятнее. Вот я и решил, что это может быть полезным не только мне. |
|
27-03-2006 23:302 Юрий Спектор:
Не могли бы Вы пояснить, чем описанный здесь способ принципиально лучше использования TComponent (поддержка которого в TStream уже есть)? |
|
27-03-2006 09:24Как раз искал как сохранить запись, содержащий массивы с динамическим AnsiString в файл, надеюсь материал поможет.... |
|
|
|