Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Von TStringList abgeleitete Klasse inkl. Objecten speichern (https://www.delphipraxis.net/152838-von-tstringlist-abgeleitete-klasse-inkl-objecten-speichern.html)

Schwedenbitter 8. Jul 2010 21:36

Von TStringList abgeleitete Klasse inkl. Objecten speichern
 
Hallo,

Grundproblem:
Ich möchte in meinem Programm viele Daten verwalten. Diese Daten speichere ich nicht in Records, sondern in TmeineDaten = Class(TObject) End; TmeineDaten enthält dann Strings, Integer und alles mögliche andere.
Diese Objecte wiederum verwalte ich alle in einer TStringList; TStringList deshalb, weil die Objecte alle mit Ihrem Namen abgelegt werden und ich dann über Index:=IndexOf('irgendwas') bzw. z.B. (Objects[Index] As TmeineDaten).TollerString:='Hallo'; gut drankomme.
Mir ist SaveToFile() bekannt, was aber die Inhalte meiner Objects nicht mit speichert. TFileStream.WriteComponent() klappt leider auch nicht, weil ich meine Klasse nicht von TComponent abgeleitet habe... Ich möchte gern eine Methode SaveToFile() in meiner Haupt-Klasse (eben abgeleitet von TStringList) implemetieren, die die Object-Daten mit speichert und ohne einen riesigen Aufwand zu machen.
[edit]Ziel ist es später beim Programmstart, die ganzen Daten wieder in die Liste laden zu können[/edit]

Gibt es hierfür eine Lösung/Ideen?

Ich hoffe, mein Problem verständlich rübergebracht zu haben. Falls trotzdem Fragen sind, bitte stellen!

Danke, Alex

daywalker9 8. Jul 2010 21:52

AW: Von TStringList abgeleitete Klasse inkl. Objecten speichern
 
Du könntest eine Klasse von TStringList ableiten mit einem eigenen SaveToFile. Dort machst du für jedes Attribut, das du hast, mit z.b. einem MemoryStream WriteBuffer.

Delphi-Quellcode:
type
  TMeinDaten = class
  property ABC : integer read fAbc write fAbc;
  end;

  //deine savetofile funktion

  ms:=TMemoryStream.create;
  ms.WriteBuffer(meinedaten.abc,sizeof(meinedaten.abc)); //usw, falls mehrere attrbute
  ms.savetofile('MeinDateiname.abc');
  ms.free;
Zum auslesen machst du einfach das gleich wie beim Speichern nur eben ReadBuffer

Schwedenbitter 8. Jul 2010 22:04

AW: Von TStringList abgeleitete Klasse inkl. Objecten speichern
 
Danke für die Antwort!

Die Idee ist gut, aber in meinem Fall nicht praktikabel.
Habe ich doch tatsächlich vergessen zu erwähnen, dass ich das ganze später natürlich wieder laden möchte (geändert, siehe oben). Das Problem ist, dass ich dann jedes Object wieder initialiseren muss etc. pp. Das erzeugt damit einen riesigen overhead.
Im Grunde könnte ich das alles in einer DB in verschiedenen Tabellen speichern. Daran wollte ich mich eigentlich vorbeimogeln. Und ich habe ehrlich gesagt noch nie mit DB in Delphi gearbeitet. Ich habe schon ein wenig mit MySQL experimentiert. Ich wollte aber auch ausdrücklich verhindern, dass ich einen Server aufsetzen muss.

Gruß, Alex

daywalker9 8. Jul 2010 22:13

AW: Von TStringList abgeleitete Klasse inkl. Objecten speichern
 
Nun ja, du könntest den Firebird Embedded Server benutzen. Dann brauchst du nichts installieren, nur die gds32.dll mit ausliefern. Und Komponenten für den Zugriff gibts genug. FIBPlus, Zeos usw...

Und so schwer ist DB auch nicht

jfheins 8. Jul 2010 22:14

AW: Von TStringList abgeleitete Klasse inkl. Objecten speichern
 
Naja, also deine Objekte sollten schon eine SaveToStream() Methode mitbringen. Dann kannst du in der StringList einfach die SavetoStream() methode überschreiben und jeweils immer die Länge des Namens, den Namen selbst speichern und dann SaveToStream() aufrufen.
Das ist dann zwar ein (unleserliches) Binärformat, und es ist auch ruck-zuck inkompatibel mit Vorgänger/Nachfolgeversionen, aber es geht und nimmt wenig Platz ein :mrgreen:

Also TmeineDaten um ein SaveToStream() erweitern (savetofile kannst du der Vollständigkeit halber auch direkt dazutun), und dann sowas machen:
Delphi-Quellcode:
Stream.Write(Items.Count)
for i := 0 to Items.Count - 1 do
begin
  Stream.Write(Items[i].length);
  Stream.Write(Items[i]);
  Stream.Write((Objects[i] as TmeineDaten).SaveToStream(Stream));
end;

Namenloser 9. Jul 2010 02:29

AW: Von TStringList abgeleitete Klasse inkl. Objecten speichern
 
Zitat:

Zitat von Schwedenbitter (Beitrag 1034390)
TFileStream.WriteComponent() klappt leider auch nicht, weil ich meine Klasse nicht von TComponent abgeleitet habe...

Du musst gar nicht von TComponent ableiten! Es reicht auch, wenn du von TPersistent ableitest. Wenn das auch nicht geht, weil z.B. die Klasse schon einen anderen Vorfahren hat, kannst du immer noch per Compilerschalter die RTTI für deine Klasse aktivieren:
Delphi-Quellcode:
type
{$M+}
TMyClass = class(TObject)
private
  FX: integer;
published
  property X: integer read FX write FX;
  ...
end;
{$M-}
Du musst nur darauf achten, dass alles was gespeichert werden soll im published-Abschnitt steht.

Schwedenbitter 9. Jul 2010 07:22

AW: Von TStringList abgeleitete Klasse inkl. Objecten speichern
 
Danke für die Tipps!

So klappt es leider nicht:
Delphi-Quellcode:
   {$M+}
   TDishList= Class(TStringList)                  // Object für Liste der Gerichte
              Private
                  Function GetSystemID(Index: Integer): Integer;
                  Procedure SetSystemID(Index: Integer; Const Value: Integer);
              Public
                  Constructor Create;
                  Destructor Destroy; Override;
                  Function AddDish(Value: TDishes): Integer;
                  Procedure DeleteDish(Index: Integer);
                  Procedure SaveToFile(Const FileName: String); Override;
                  Procedure LoadFromFile(Const FileName: String); Override;
                  Property SystemID[Index: Integer]: Integer
                     Read GetSystemID Write SetSystemID;
              End;
   {$M-}

// Liste in eine Datei speichern
Procedure TDishList.SaveToFile(Const FileName: String);
Var
   I            : Integer;
Begin
   If Count < 1 Then Exit;                        // es muss mind. 1 Eintrag da sein
   With TMemoryStream.Create Do
   Try
      WriteComponent(self);                     // <- inkompatible Typen
      SaveToFile(FileName);                     // alles in der Datei ablegen
   Finally
      Free;
   End;
End;
Wo ist hier mein Denkfehler?

Ich kann leider im Public-Bereich nichts vorweisen. Denn das Object selbst ist ja die Liste. Ich hatte auch versucht, mein Object von TComponent abzuleiten und in Public eine TStringList zu deklarieren. Das geht an sich. Beim Speichern bekomme ich aber auch immer nur eine Datei die 17 Bytes groß ist ...

Gruß, Alex

idefix2 9. Jul 2010 09:20

AW: Von TStringList abgeleitete Klasse inkl. Objecten speichern
 
Ein inherited in savetofile wäre sicher hilfreich

Wie das derzeit ohne Endlosschleife funktioniert, verteh ich nicht.
Sobald count >0 ist, ruft savetofile sich selbst doch rekursiv auf, ohne Abbruchbedingung für die Rekursion?
Vermutlich löst WriteComponent eine Exception aus, sonst müsste das Programm da abstürzen

edit - Blödsinn, in die with Falle gestolpert - solche Konstruktionen gehören veboten :) Mit dem with erreicht man in solchen Fällen wirklich nur, dass man den Code endlos studieren muss, um herauszufinden welche Variable da wo gewitht wird.
Aber ohne inherited wird es nicht gehen.

Schwedenbitter 9. Jul 2010 09:43

AW: Von TStringList abgeleitete Klasse inkl. Objecten speichern
 
Zitat:

Zitat von idefix2 (Beitrag 1034429)
Aber ohne inherited wird es nicht gehen.

Das glaube ich nicht wirklich.
Denn mein Object erbt die Methode SaveToFile() abgeleitet von TStringList. Das wiederum speichert ja nur die einzelnen Listeneinträge in einer Datei. Ich kann mir daher nicht vorstellen, dass ein inherited irgend etwas bzgl. der mit der Liste gespeicherten Objecte bewirken soll.

Im Moment sieht mein Code - sehr sehr unschön - so aus:
Delphi-Quellcode:
Type
   TDish      = Record                              // Record zum abspeichern
                  SystemID      : Integer;
                  DishName      : String[255];
                  DishType      : Integer;
                  Price         : Currency;
              End;

// Liste in eine Datei speichern
Procedure TDishList.SaveToFile(Const FileName: String);
Var
   I            : Integer;
   Buffer      : TDish;
   OutFile      : File Of TDish;
Begin
   If Count < 1 Then Exit;                        // es muss mind. 1 Eintrag da sein

   AssignFile(OutFile, FileName);               // Dateiname zuweisen
   {$I-}
   FileSetAttr(FileName, $00);                  // alle Attribute löschen
   DeleteFile(PAnsiChar(FileName));               // Datei löschen und
   ReWrite(OutFile);                              // neu anlegen
   For I:=0 To Pred(Count) Do                     // gesamte Liste durchgehen
   Begin
      FillChar(Buffer, SizeOf(Buffer), 0);      // Puffer leeren
      Buffer.SystemID:=(Objects[I] As TDishes).SystemID;
      Buffer.DishName:=(Objects[I] As TDishes).DishName;
      Buffer.DishType:=(Objects[I] As TDishes).DishType;
      Buffer.Price:=     (Objects[I] As TDishes).Price;
      Write(OutFile, Buffer);                     // Daten in Datei ablegen
   End;
   CloseFile(OutFile);                           // die Datei schließen
   {$I+}
End;
Das laden dann analog. Aber das ist umständlich und kompliziert. Und wenn man das später mal warten will, dann muss man statt 5-7 Zeilen für WriteComponent() eben diese vielen behandeln.

Gruß, Alex

P.S. Ich liebe im Übrigen das With! Wenn ich größere Objecte habe, in denen ich - als welchen Gründe auch immer - bestimmte Properties in der Registry oder sonstwie speichern muss, dann spare ich mir etliche Zeilen Code auf diese Art und Weise. Das ist aber nur meine persönliche Meinung.

mkinzler 9. Jul 2010 09:47

AW: Von TStringList abgeleitete Klasse inkl. Objecten speichern
 
Gerade bei großen Blöcken kann
Delphi-Quellcode:
with
aber zu großen Problemen/Seiteneffekten führen


Alle Zeitangaben in WEZ +1. Es ist jetzt 12:55 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz