[DELPHI] Variablen mit Inhalt in Datei speichern

deadzoneman

Lt. Junior Grade
Registriert
Jan. 2003
Beiträge
347
hi,
hab jetzt mal versucht, nen verwaltungsprog zu erstellen, wo man zum beispiel name, rasse usw. eingeben kann, diese daten kann man speichern und später wieder abrufen. das funzt jetzt auch alles, zumindest solange bis jemand das prog beendet, es neu startet und dann versucht die datei zu laden. das geht dann nicht mehr, wenn das prog allerdings noch läuft, wenn der user es vorher gespeichert und dann lädt, geht es. ich hab zwar die vermutung, dass er, wenn er die variableninhalte speichert (in einer TextFile mit .dat-endung), nur den inhalt speichert, den aber nicht mehr lesen kann, da die variable gelöscht wurde beim enden des prog. zu deutsch, dass die variablen nicht mehr ausgelesen werden können.

(wichtigeren) teile des codes:

Code:
... type
  inhalt = record
    NameCh, NameSp, Klasse, Volk, Gesinnung, Gottheit, Geschlecht,
    Haarfarbe, Hautfarbe, ... : string;
end;
...

var daten : inhalt;
...
procedure TFormCErschaffung.ButtonSpeichernClick(Sender: TObject);
var name:string;
    datei:textfile;
begin
if SaveDialog.Execute then begin
wertaufnahme;
name:=FormCErschaffung.savedialog.filename;
try
    assignfile(datei, name);
    rewrite(datei);
    writeln(datei,daten.NameCh);
    writeln(datei,daten.NameSp );
    writeln(datei,daten.Klasse );
    writeln(datei,daten.Volk );
    writeln(datei,daten.Gesinnung );
    ...
    writeln(datei,daten.ModWei );
    writeln(datei,daten.ModCha );
    closefile(datei);
    messagedlg('Erfolgreich gespeichert !',mtinformation,[mbok],0);
    except
    messagedlg('Fehler beim speichern!!!!!!!(is kein Witz)',mtinformation,[mbok],0);
    exit;
end;
end;
end;
...
procedure TFormCErschaffung.wertaufnahme;
begin
daten.NameCh:=NameCh;
daten.NameSP:=NameSP;
daten.Klasse:=Klasse;
daten.Volk:=Volk;
daten.Gesinnung:=Gesinnung;
daten.ModWei:=ModWei;
daten.ModCha:=ModCha;
end;

...

procedure TFormCErschaffung.wertabgabe;
begin
FormCErschaffung.EditNameCh.Text:=daten.NameCh;
FormCErschaffung.EditNameSp.Text:=daten.NameSP;
FormCErschaffung.ComboBoxKlasse.Text:=daten.Klasse;
FormCErschaffung.ComboBoxVolk.Text:=daten.Volk;
FormCErschaffung.ComboBoxGesinnung.Text:=daten.Gesinnung;
FormCErschaffung.EditWeiMod.Text:=IntToStr(daten.ModWei);
FormCErschaffung.EditChaMod.Text:=IntToStr(daten.ModCha);
end;
...
procedure TFormCErschaffung.ButtonLoeschenClick(Sender: TObject);
var name:string;
    datei:textfile;
begin
if OpenDialog.Execute then begin
name:=FormCErschaffung.savedialog.filename;
try
    assignfile(datei, name);
    reset(datei);
    readln(datei, daten.NameCh);
    readln(datei, daten.NameSp );
    readln(datei, daten.Klasse );
    readln(datei, daten.Volk );
    readln(datei, daten.Gesinnung );
    readln(datei, daten.Gottheit );
   ...
readln(datei, daten.ModWei );
    readln(datei, daten.ModCha );
    closefile(datei);
    wertabgabe;
    messagedlg('Erfolgreich geladen !',mtinformation,[mbok],0);
    except
    messagedlg('Fehler beim Laden!!!!!!!(is kein Witz)',mtinformation,[mbok],0);
    exit;
end;
end;
end;

falls das zu unübersihtlich war, kann ich auch nochmal den kompletten code schicken.

die fehler meldung ist, wenn ich versuche zu laden :
"Project DunDAssisten.exe raised exception class EInOutError with message I/O error 104. Process stopped. Use step or run to continue." (erscheint in nem extra dialogfeld mit nem weißen x auf rotem grund)

hat jemand ne idee? soll ich die als typisierte datei speichern? und wenn ja wie? oder woran kanns sonst liegen?

thy

deaddy
 
Uh oh, das sind ja noch die uralten Pascal-Funktionen :-)

Ich würde Dir raten, davon abzulassen und stattdessen eine StringList zu benutzen.

Code:
procedure TFormCErschaffung.ButtonSpeichernClick(Sender: TObject);
var
  name:string;
  SL: TStringList;
begin
  if not SaveDialog.Execute then Exit;
  wertaufnahme;
  name := savedialog.filename;

  SL := TStringList; // erzeugt eine neue Stringlist. Die ist am Anfang immer leer.
  try
    SL.Append (daten.NameCH); // Daten nacheinander der Liste anhängen
    SL.Append (daten.NameSP);
    ...
    SL.SaveToFile (name); // abspeichern
  finally
    SL.Free; // was man erzeugt, muss man auch wieder freigeben :)
  end;
end;
Das Laden wäre dann analog mit SL.LoadFromFile, und dann gehst Du wie folgt über die Liste:

Code:
....
  SL.LoadFromFile (name); // und wieder laden
  if (SL.Count < Anzahl) then // Anzahl ist die minimale Anzahl an Zeilen, die Du brauchst
     // Fehlermeldung
  daten.NameCh := SL [0]; // den ersten String aus der Datei zuweisen
  daten.NameSp := SL [1];
  ....
 
Zuletzt bearbeitet:
mach dir eine
file of inhalt (dein record)
und speicher mit write(daten); (deine Recordvariable)

lesen geht dann analog mit read(daten);
 
Hm das halte ich für keine gute Idee. Wenn man wirklich eine typisierte Datei macht, dann müssen die Strings unbedingt auch eine feste Länge haben. An dieser Stelle muss man dann zwangsläufig den alten Shortstring benutzen, mit Ansistrings geht das so nicht. Außerdem finde ich, dass wenn man die Datei human readable macht, hat man wesentlich mehr davon.
 
Also wenn du auf übertragbare Formate wert legst, bleibt ja nur folgendes:

1 Datensatz pro Zeile und die Werte des Datensatzes durch Tabulatoren voneinander getrennt.
Damit ist es kompatibel zu php,excel,word und der bde ;)

wäre dann also in etwa

Code:
    Var
      datei:Textfile;
      vtempstr:string;
    Begin
    assignfile(datei, name);
    rewrite(datei);
    vtempstr:=daten.NameCh;
    vtempstr:=vtempstr+chr(9)+daten.NameSp ;
    vtempstr:=vtempstr+chr(9)+daten.Klasse ;
    vtempstr:=vtempstr+chr(9)+daten.Volk ;
    vtempstr:=vtempstr+chr(9)+daten.Gesinnung ;
    ...
    vtempstr:=vtempstr+chr(9)+daten.ModWei ;
    vtempstr:=vtempstr+chr(9)+daten.ModCha;
    writeln(datei,vtempstr);
    closefile(datei);
End;

Auslesen gestaltet sich dann aber etwas schwerer, ist aber auch einfach lösbar.
Einfach zeilenweise auslesen und nach Tabulatoren (chr(9)) durchsuchen und an dieser Stelle entsprechend splitten.
 
Toaster schrieb:
Hi,

ich würde dafür WritePrivateProfileString & GetPrivateProfileString aus der WinAPI nutzen, für solche Sachen finde ich Inifiles irgendwie am komfortabelsten.

Gruß

Toaster
Dafür hat Delphi das TIniFile Objekt, dass diese Funktionen wirklich sehr gut kapselt. Wenn man es benutzen will, muss man die Unit IniFiles in der uses-Klausel angeben.

..ooOO ( Irgendwie wir deadzoneman grad überflutet mit Infos :) )
 
eieiei, thx, das sind wirklich viele antworten.
ich hab das nun als stringlist geschrieben (das prog soll sowieso nur ne äußerst komplizierte übung werden, vorbereitend auf mein hauptprojekt...). hat zwar nen bisschen gedauert weil ich was umschreiben musste, und als mir auffiel, dass das umschreiben irgendwie unnötig war, und alles dan wieder zurückschreiben musste, funzt jetzt aber problemlos. wenn ich damit fertig bin, kann ichs ja noch ma uploaden.
 
7H3 N4C3R schrieb:
Hm das halte ich für keine gute Idee. Wenn man wirklich eine typisierte Datei macht, dann müssen die Strings unbedingt auch eine feste Länge haben. An dieser Stelle muss man dann zwangsläufig den alten Shortstring benutzen, mit Ansistrings geht das so nicht. Außerdem finde ich, dass wenn man die Datei human readable macht, hat man wesentlich mehr davon.

Auch wenn der Thread schon etwas älter ist, es scheint mir doch sinnvoll dazu noch etwas zu schreiben :)
Man kann sehr wohl Ansistrings verwenden. Man muss eben ein array of record erstellen, die Variablen dieses record(s) anschließend dereferenzieren und mit Hilfe von Streams in eine Datei schreiben. Auslesen geht auch ganz einfach mit Read, das komplette Array wird ja wieder zurückgeliefert und man kann wie gewohnt darauf zugreifen.
 
Deshalb schreib ich ja "geht so nicht" :)

Bin mir aber nicht so sicher, ob Deine Lösung funktioniert.. Dazu müsste der Stream-Handler wissen, wie er einen String zu schreiben hat. Und das Rausschreiben eines Ansi-Strings ist sowieso immer schwierig, da der Aufbau meines Wissens wie folgt ist [4 Bytes Referenzzähler][Daten][terminierende Null für char* Kompatiblität]. Das größte Problem sollte der Referenzzähler sein, da man den nicht einfach schreiben und wieder lesen darf. (Man kann schon, führt aber unweigerlich zu Problemen) Außerdem sollte die Datei dann nicht mehr typisiert sein, was ja das eigentliche Ziel war.
 
Zuletzt bearbeitet:
7H3 N4C3R schrieb:
Deshalb schreib ich ja "geht so nicht" :)

Bin mir aber nicht so sicher, ob Deine Lösung funktioniert.. Dazu müsste der Stream-Handler wissen, wie er einen String zu schreiben hat. Und das Rausschreiben eines Ansi-Strings ist sowieso immer schwierig, da der Aufbau meines Wissens wie folgt ist [4 Bytes Referenzzähler][Daten][terminierende Null für char* Kompatiblität]. Das größte Problem sollte der Referenzzähler sein, da man den nicht einfach schreiben und wieder lesen darf. (Man kann schon, führt aber unweigerlich zu Problemen) Außerdem sollte die Datei dann nicht mehr typisiert sein, was ja das eigentliche Ziel war.

Also bei mir geht das so problemlos :). Als Trennzeichen wird automatisch ein 06 00 00 00 (HEX) verwendet, anschließend lese ich das ganze wieder ein als Stream und kann den Inhalt wieder als array of [TMyType] verwenden.
 
Zurück
Oben