Форум: "Основная";
Текущий архив: 2003.11.20;
Скачать: [xml.tar.bz2];
ВнизСохранение сложных объектов Найти похожие ветки
← →
Walrus (2003-11-07 18:45) [0]Всем доброго времени суток!
Есть у меня объект класса А, который содержит в себе список( можно коллекцию - не важно ) объектов класса В, а каждый объект класса В содержит список объектов класса С. Ну, разумеется там не по одному списку и есть другие поля - я упрощённо описываю. Так вот надо сохранить объект класса А в файл( БД нельзя использовать ), чтоб при следующем запуске программы система заработала в том состоянии, в котором её работу прервали. Как Вы, наверное, поняли количество элементов ни в одном списке не известно заранее:(
← →
me (2003-11-07 20:09) [1]удобно писать в XML-файл, в сети масса примеров сериализации дельфовых объектов в XML
← →
Игорь Шевченко (2003-11-07 20:21) [2]Stream
← →
Walrus (2003-11-07 22:25) [3]me, спасибо, поищем... будет вообще супер, если кинешь ссылочку.
Игорь Шевченко, спасибо.
Со Stream у меня и возникли проблемы. Класс А было решено унаследовать от TComponent и в нём сделать TCollection объектов класса В, а в классах В TStringList из объектов класса С. Потом запись
var
ms : TMemoryStream;
fs : TFileStream;
a_Obect : A;
.... //тут всё создаётся и инициализируется
ms.WriteComponent( a_object );
ObjectBinaryToText( ms, fs );
В итоге потом из файла удаётся восстановить всё, кроме списка
TStringList. Я его заполняю, сохраняю, а при следующем запуске в нём 0 элементов! В чём тут может быть дело( кроме моей кориворукости :) )?
← →
Игорь Шевченко (2003-11-07 22:41) [4]А свойство, имеющее тип StringList объявлено, как published ? Наследники TComponent сохраняют/восстанавливают только published свойства, если не объявлен метод DefineProperties. Лучше было, если бы был приведен код с типами объектов.
← →
Walrus (2003-11-07 22:50) [5]Игорь Шевченко, огромное спасибо! Дело именно в атрибуте доступа.
← →
Walrus (2003-11-07 23:23) [6]Так, похоже вопросы остались.
Раньше в TStringList сохранялись только строки( просто потому, что пробовали - как это вообще работает ), теперь добавляем объект( ради этого собственно и брали TStringList ) и он не сохраняется в файл. Почему я так думаю: потому что при попытке его загрузить выдаётся исключение. А вот и код. Не хотелось напрягать, ведь читать чужой код это...но иначе никак:( Класс А -TMailer; класс В - TMailClient; для удобства список не прямо коллекцией сделан, а организован как его потомок - TMailList; класс С - TMy_Connection. Код урезан по максимуму от всякой лишней ерунды.
unit Mailer_ProgrC;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Label1: TLabel;
Label2: TLabel;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
TMy_Connection = class
public //обернуть в свойство
ID : integer;
constructor Create( value : integer );
end;
TMailClient = class( TCollectionItem )
private
FFolders : TStringList;
public
name : string;
constructor Create( Collection : TCollection ); override;
destructor Destroy; override;
published
property Folders : TStringList read FFolders write FFolders;
end;
TMailList = class( TCollection )
public
function GetMailClient( Index : Integer ) : TMailClient;
procedure SetMailClient( Index : Integer; value : TmailClient );
function Add : TmailClient;
property Items[ Index : Integer ] : TMailClient read GetMailClient
write SetMailClient; default;
end;
TMailer = class( Tcomponent )
private
FMailList : TMailList;
public
constructor Create( AOwner : TComponent ); override;
destructor Destroy; override;
published
property MailList : TMailList read FMailList write FMailList;
end;
var
Form1: TForm1;
Mailer : Tmailer;
implementation
{$R *.dfm}
constructor TMy_Connection.Create ( value : integer );
begin
ID := value;
end;
constructor TmailClient.Create( Collection : TCollection );
begin
inherited;
Folders := TStringList.Create;
name := "name1";
end;
destructor TMailClient.Destroy;
begin
Folders.Free;
inherited;
end;
function TmailList.GetMailClient( Index : Integer ) : TMailClient;
begin
Result := TmailClient( inherited Items[ Index ] );
end;
procedure TMailList.SetmailClient( Index : Integer; Value : TmailClient );
begin
Items[ Index ].Assign( Value );
end;
function TMailList.Add : TMailClient;
begin
Result := TMailClient( inherited Add );
end;
constructor TMailer.Create( AOwner : Tcomponent );
begin
inherited Create( AOwner );
MailList := TMailList.Create( TMailClient );
end;
destructor TMailer.Destroy;
begin
MailList.Free;
inherited;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
m : TMailClient;
ms : TMemoryStream;
fs : TFileStream;
count : integer;
con : TMy_Connection;
begin
Mailer := Tmailer.Create( self );
fs := TFileStream.Create( ExtractFilePath( ParamStr( 0 ) ) + "user.dat",
fmOpenread );
ms := TmemoryStream.Create;
try
ObjectTextToBinary( fs, ms );
ms.Position := 0;
ms.ReadComponent( Mailer );
finally
ms.Free;
fs.Free;
end;
count := Mailer.MailList[1].Folders.Count;
label1.Caption := IntToStr(TMy_Connection(Mailer.MailList[1].Folders.Objects[ count - 1 ]).ID);
con := TMy_Connection.Create( 123 );
Mailer.MailList[1].Folders.AddObject( "hhh",con );
end;
procedure TForm1.FormDestroy(Sender: TObject);
var ms : TMemoryStream;
fs : TFileStream;
begin
fs := TFileStream.Create( ExtractFilePath( ParamStr( 0 ) ) + "user.dat",
fmCreate or fmOpenWrite );
ms := TMemoryStream.Create;
try
ms.WriteComponent( Mailer );
ms.position := 0;
ObjectBinaryToText( ms, fs );
finally
ms.Free;
fs.Free;
end;
end;
end.
← →
Игорь Шевченко (2003-11-07 23:58) [7]Да, TStringList объекты свои не сохраняет (не умеет).
Чтобы научить его, нужно у TMailClient определить процедуру DefineProperties (определена у всех наследников TPersistent), например
type TMailClient = class(...)
.....
private
procedure ReadFolders (Reader : TReader);
procedure WriteFolders (Writer : TWriter);
protected
procedure DefineProperties(Filer : TFiler); override;
....
end;
...
procedure TMailClient.DefineProperties(Filer: TFiler);
function DoWriteFolders : Boolean;
begin
Result := FFolders.Count > 0;
end;
begin
inherited;
Filer.DefineProperty("Folders", ReadFolders, WriteFolders, DoWriteFolders);
end;
....
procedure TMailClient.ReadFolders(Reader: TReader);
var
S : String;
begin
FFolders.Clear();
Reader.ReadListBegin();
while not Reader.EndOfList do begin
S := Reader.ReadString;
FFolders.AddObject(S, Reader.ReadComponent(nil));
//Подразумевается, что в Objects находятся наследники TComponent
Reader.ReadListEnd();
end;
end;
procedure TTransObject.WriteFolders(Writer: TWriter);
var
I : Integer;
begin
Writer.WriteListBegin();
for I:=0 to Pred(FFolders.Count) do begin
Writer.WriteString(FFolders[I]);
//Подразумевается, что в Objects находятся наследники TComponent
Writer.WriteComponent(FFolders.Objects[I]);
end;
Writer.WriteListEnd();
end;
Или, как второй вариант, написать наследника TStringList, коотрый умеет в методах LoadFromStream/SaveToStream сохранять объекты в Objects
С уважением,
← →
Walrus (2003-11-08 20:17) [8]Игорь Шевченко, да, спасибо. Только не совсем ясно
в методе ReadFolders(...)
FFolders.AddObject(S, Reader.ReadComponent(nil));
Почему NIL? Там на самом деле локальная переменная, которую мне надо объявить?
И возникла проблема с наследованием элементов, которые поселяем в TStringList, от TComponent:они у нас от TCollectionItem, т.е. оказалось проще отказаться от TStringList в пользу TCollection, иначе там что-то надо с интерфейсами делать? Я правильно всё путаю?
← →
Игорь Шевченко (2003-11-08 21:15) [9]Walrus (08.11.03 20:17)
nil потому что Reader должен создать компонент и прочитать его свойства, а не читать свойства в заранее созданный.
Если от TCollectionItem, тогда TCollection сама умеет вроде сохранять/читать из потока
← →
mc_duck (2003-11-08 21:29) [10]А с какой целью делается следущее:
ms.WriteComponent( a_object );
ObjectBinaryToText( ms, fs );
Если сразу в файловый поток писать,то что?
← →
Walrus (2003-11-08 21:59) [11]Игорь Шевченко, да сохраняет, теперь так и работаем. Просто мне настойчиво внушали, будто TStringList меньше места занимает и с ним быстрее. При попытке добиться аргументов такого мнения мне ничего не ответили. Кто-нибудь может прояснить ситуацию?
mc_duck, сейчас проведём эксперимент по записи двоичных данных в текстовый файл. Ждите отчёта. :)
← →
Игорь Шевченко (2003-11-08 22:14) [12]Walrus (08.11.03 21:59)
Если и меньше, то ненамного, достаточно посмотреть в Classes.pas
← →
mc_duck (2003-11-08 22:15) [13]У меня в программе есть класс
TConDisTrig = class(TPaintBox)
public
fTimer:TTimer;
...
published
property Timer:TTimer read fTimer write fTimer;
...
end;
Объект TConDisTrig сохраняется,но не сохраняются свойства fTimer.
В чем дело?
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2003.11.20;
Скачать: [xml.tar.bz2];
Память: 0.49 MB
Время: 0.01 c