Bonjour à tous,

Voici ma situation : Je désire écrire les objets complexes (contenant différents objets eux-mêmes ou des listes d'objets) dans un fichier binaire.

Comme plusieurs d'entre-vous le savez déjà, il existe de plusieurs façons d'écrire dans un fichier binaire. Delphi étant très axé "components writing" (tel que dans un .DFM) et que mes objets ne sont pas des composants, j'ai cherché sur google, les newsgroup, les forums (incluant celui-ci) et l'aide de Delphi pour un moyen détourné.

Dans l'aide de Delphi, j'ai trouvé un exemple qui utilise les méthodes :
WriteComponentResFile
et
ReadComponentResFile

L'exemple crée une classe container contenant l'objet dans une property publié (published - seuls les property published sont streamer).

Puis l'exemple crée une autre classe appelé : TStreamableClass qui va publié le conteneur. Ces classes sont enregistrés ( RegisterClasses() ) afin que le RTTI (Run Time Type Information) puisse les reconnaître et les traitées.

L'exemple fonctionne très bien et les attributs membres de type integer et string sont écrits et lus. Cependant, si j'ajoute un objet dans la classe TContainer, en prenant soin de placer la property dans la section published et enregistrer la classe et cette classe hérite de TPersistent (pour qu'elle soit streamer) et les property de cette classe dans la section published.... l'objet n'est pas lu. Je ne sais pas si l'objet est écrit ou non.

Voici l'exemple de l'aide de Delphi que j'ai modifié (3 units):

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
 
{Dans la form. ajouté un bouton et ajouté dans l'event OnClick la procédure ci-dessous}
 
unit ProjetStreamExemple;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, StrmExmpl;
 
type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Déclarations privées }
  public
    { Déclarations publiques }
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.dfm}
 
procedure TForm1.Button1Click(Sender: TObject);
var
  AClassInstance: TStreamableClass;
begin
  AClassInstance := TStreamableClass.Create(nil);
  WriteComponentResFile('C:\Test', AClassInstance);
  FreeAndNil(AClassInstance);
 
  AClassInstance := ReadComponentResFile('C:\Test', nil) as TStreamableClass;
  FreeAndNil(AClassInstance);
end;
 
end.
 
//------------------------------------
unit StrmExmpl;
{$R-,T-,H+,X+}
 
interface
 
uses Classes, Test;
 
type
 
  TContainedClass = class(TPersistent)
    private
    FSomeData: Integer;
    FSomeTest : TTest;
    SSomeString : string;
    procedure SetSomeData(Value: Integer);
    procedure SetSomeTest(Value: Ttest);
    function LireSomeTest: Ttest;
    procedure SetSomeString(const Value: string);
 
    public
 
    constructor Create;
 
    // Seules les propriétés publiées
    // sont mises automatiquement dans le flux.
    published
 
    property SomeData: Integer read FSomeData write SetSomeData;
    property SomeTest: Ttest read LireSomeTest write SetSomeTest;
    property SomeString : string read SSomeString write SetSomeString;
  end;
 
 
  TStreamableClass = class(TComponent)
    private
    FContainedClass: TContainedClass;
    public
    constructor Create(AOwner: TComponent); override;
 
 
    destructor Destroy; override;
 
    // Seules les propriétés publiées
    // sont mises automatiquement dans le flux.
    published
 
    property ContainedClass: TContainedClass read FContainedClass write FContainedClass;
 
  end;
 
implementation
 
procedure TContainedClass.SetSomeData(Value: Integer);
begin
{ Placer un point d'arrêt ici et remarquer comment les données reviennent dans le flux. }
  FSomeData := Value;
end;
 
procedure TContainedClass.SetSomeTest(Value: Ttest);
begin
  FSomeTest := Value;
end;
 
constructor TContainedClass.Create;
begin
  FSomeData := 42;
  SSomeString := 'Adam';
  FSomeTest := TTest.create;
end;
 
constructor TStreamableClass.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FContainedClass := TContainedClass.Create;
end;
 
destructor TStreamableClass.Destroy;
begin
  FContainedClass.Free;
end;
 
function TContainedClass.LireSomeTest: Ttest;
begin
  Result := FSomeTest;
end;
 
procedure TContainedClass.SetSomeString(const Value: string);
begin
  SSomeString := Value;
end;
 
initialization
  RegisterClasses([TContainedClass, TTest, TStreamableClass]);
finalization
 
end.
 
//-------------------------------------------------------------------------------
unit Test;
 
interface
 
uses Classes;
 
type
  Ttest = class(TPersistent)
  private
    fValue : string;
    sValue : integer;
    function ReadValue1: string;
    function ReadValue2: integer;
    procedure WriteValue1(const Value: string);
    procedure WriteValue2(const Value: integer);
  public
    constructor Create;
  published
    property Value1 : string read ReadValue1 write WriteValue1;
    property Value2 : integer read ReadValue2 write WriteValue2;
  end;
 
implementation
 
{ Ttest }
 
constructor Ttest.Create;
begin
  inherited create;
  fValue := 'Adam';
  sValue := 1;
end;
 
function Ttest.ReadValue1: string;
begin
  Result := fValue;
end;
 
function Ttest.ReadValue2: integer;
begin
  Result := sValue;
end;
 
procedure Ttest.WriteValue1(const Value: string);
begin
  fValue := Value;
end;
 
procedure Ttest.WriteValue2(const Value: integer);
begin
  sValue := Value;
end;
 
end.
Ma question est la suivante : est-ce qu'il est possible d'écrire et de lire l'objet de la classe TTest selon cette méthode ?

Je ne peux pas utilisé les TCollections et TCollectionItem car dans mon programme principal (pas cet exemple), les objets contiennent une liste d'objets différents.

J'aimerais pouvoir éviter d'écrire chaque objet individuellement en créant des nouvelles fonctions de streaming, spécifiant la taille des string, integer et autre avant.... à cause de la complexité du programme principal.

Merci à l'avance,

Andalarius