Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Klassen in Streams speichern und wiederherstellen


Dezipaitor - Mi 14.05.03 18:30
Titel: Klassen in Streams speichern und wiederherstellen
ich habe mehrere Klassen die voneinander abgeleitet sind und immer zusätzliche Daten enthalten. die erste Klasse (TItem) ist abgeleitet von TPersistent und wird in funktionen verwendet, um einen gemeinsamen nenner bei der datenanylse (in den klassen) zu erhalten.

ich habe diese verschiedenen klassen in eine TList gespeichert, und speichere sie in einen stream indem ich einfach den Pointer in die erste Klasse TItem typecaste, und die virtuelle methode Store, zum speichern der Daten aufrufe. dann werde ja die überschriebenen methoden store der gespeicherten Klassen (alle sind ja von TItem abgeleitet) aufgerufen.

so nu sollen alle klassen wieder geladen werden. aber um alle klassen wiederherzustellen muss ich doch genau die klassen wieder laden, die gespeichert wurden. aber woher weiß ich welcher klassentype geschrieben wurde?

um eine klasse zu laden wird ja zuersteinmal Create mit dem KlassenTyp aufgerufen, und dann sollte Load aufgerufen werden, um die eigenschaften zu belegen. ich könnte ja TItem.Create verwenden, aber dann werden ja bei Load nur die Daten geladen, die in TItem.Load definiert wurden. Wenn nun eine Klasse abgeleitet von TItem mehr Daten geschrieben hat (mit eigenen Store und inherited Store), aber dann weniger gelesen werden, bleiben noch einige übrig, die beim nächsten Lesen zur Verwirrung führen.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
readfromstream...
var List : TList;
      anitem : TItem;
begin
  for i := 1 to count do
   begin
      anItem := TItem.Create; //    <--- was ist wenn die gespeicherte klasse vom Typ TSubItem ist?
      anItem.Load(Stream); //
      List.Add(anitem);
end;

ich könnte natürlich den klassentyp auch speichern: z.b. ClassName oder ähnliches aber müsste dann beim laden ja unterscheiden:

Delphi-Quelltext
1:
2:
if loadedclassname = 'TSubItem' then
   anItem := TItem(TSubItem.Create);

aber bei mehreren zig Klassen ist dass wirklich umständlich.

am liebsten möchte ich den code auch unter freepascal ausführen, was für mich heißt, dass ich nur wenige VCL Klassen verwenden kann.

THX


maximus - Mi 14.05.03 18:58

das du die klasse speichern musst is klar...sonst kannst du ja, beim laden, nicht den richtigen typ ermitteln!

Dazu speicherst du den namen als string mit und vorallendingen alle deine klassen voher mit 'RegisterClass(..)' registrieren, damit du beim lesen mit 'findClass(..)' wieder an die typen kommst. Dann brauchst du auch keine expliziten if-abfragen und kannst direkt über denn klassen-typen createn :wink:

viel glück.


PS: RTTI dürfte für dich auch interresant sein -> such ma hier im forum


Dezipaitor - Mi 14.05.03 23:13

ja das system ist gut,
funktioniert leider aber nur in delphi.
ich habe es mir auch mal angesehen,
aber irgendwie kriege ich nicht raus, wie klassen gespeichert werden,
denn

freepascal steht aussen vor.
aber der code muss drunter laufen.


Udontknow - Do 15.05.03 09:09

Ja, dann speicherst du eben von hand immer vor jedem Objekt ein Identifikationsmerkmal (irgendeine Ganzzahl vom Typ Byte/Word, mehr als 16000 Klassen wirst du wohl nicht haben :wink: ). Das ist auch ein bisschen schmaler als die String-Variante, da, je nach Klassenanzahl, nur ein Byte pro Objekt gespeichert wird.

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
const itItem=0;
const itSubItem=1;

readfromstream... 
var List : TList; 
      anitem : TItem; 
var ItemClass:Byte;
begin 
  for i := 1 to count do 
   begin 
      Stream.ReadBuffer(ItemClass,Sizeof(ItemClass));
      if ItemClass=itItem then
        anItem := TItem.Create;
      if ItemClass=itSubitem then
        anItem := TSubItem.Create;
      anItem.Load(Stream); // 
      List.Add(anitem); 
end;

Vorraussetzung für diesen Codeschnipsel ist, das TItem Vorgänger aller deiner Klassen ist. Das Erzeugen solltest du vielleicht sogar in eine separate Funktion CreateFromClassID auslagern. Natürlich ist das ein wenig Arbeit. Irgendwann muss man doch noch tippen... :wink:

Cu,
Udontknow