Delphi Dateien speichern und lesen

Hallo!
In meiner Anwendung (Delphi5) möchte ich Dateien speichern und lesen. In der Datei soll der Inhalt von Variablen (z.B. ein Recordinhalt, den der Anwender in Feldern eingibt) gespeichert werden. Die Anzahl und Art der Variablen bleibt gleich.

Gleichzeitig soll beim Programmstart eine „Leerdatei (NoName.xxx)“ geöffnet werden, die, wenn der Anwender mind. 1 Feld geändert hat, vom Programm nachgefragt wird, ob die Datei gespeichert werden soll.
Im Prinzip msgDialog: "Möchten Sie die Änderungen in xxx.xxx speichern?

Wie realisiere ich das am besten?
Danke!

Sollen diese Dateien binär werden oder ASCII, wie beispielsweise INI ?

Sollen diese Dateien binär werden oder
ASCII, wie beispielsweise INI ?

Ist egal, was einfacher ist. Ist Binär denn besser?
Die Dateiendung soll „rpf“ heissen.
Hast Du eine Idee?

binär ist cooler :stuck_out_tongue:
Ich würde nen FileStream dazu benutzen.

Wenn deine Datenstruktur ned zu gross (komplex) ist, mach ich dir ein kleines Example, doch meine Zeit ist halt ein bisschen limitiert…

Aber sehr schwierig ist es nicht.

Hallo Roger!
Würde mich auch sehr interessieren! Vielleicht kannst Du ja beispielhaft hierfür die Routinen aufzeigen.
Hier mein Beispielrecord
type TMyValues=record
MyDate:TDateTime;
MyVal,MyResult:Extended;
MyString:String
MyBool:Boolean;
end;
Diese Werte sollen in einer Binärdatei gespeichert und ausgelesen werden. Ansonsten dito wie bei Helmut!
Vielen Dank!

Super!
Hier ein paar Beispieldaten:
type TDatVar=record
strName:String;
dtVom,dtBis:TDateTime;
fltErgebnis:Extended;
blnMerkmal:Boolean;
end;

Vielen Dank für Deine Mühe!
Gruß

also, hier mal was out-of-mind:

type
TMyValues = packed record
MyDate: TDateTime;
MyVal,
MyResult: Extended;
clMyString: Integer;
MyString: string;
MyBool: Boolean;
end;

var
MyValues: TMyValues;
MyFile: TFileStream;

procedure FillData;

begin
with MyValues do
begin
MyDate := now;
MyVal := 10.2;
MyResult := 12.8;
MyString := ‚Bayerische Motorenwerke‘;
MyBool := True;
end;
end;

procedure SaveToFile;

begin
MyFile := TFileStream.Create(‚test.xxx‘, fmCreare or fmShareExlusive);
with MyFile, MyValues do
begin
try
Write(MyDate, SizeOf(TDateTime));
Write(MyVal, SizeOf(Extended));
Write(MyResult, SizeOf(Extended));
clMyString := Length(MyString));
Write(clMyString, SizeOf(Integer));
Write(Pointer(MyString)^, clMyString);
Write(MyBool, SizeOf(Boolean));
Free;
except;
Free;
MessageDLG(‚Error saving File‘, mtError, [mbOK], 0);
end;
end;
end;

procedure ReadFromFile;

begin
MyFile := TFileStream.Create(‚test.xxx‘, fmOpenRead or fmShareDenyWrite);
with MyFile, MyValues do
begin
try
Read(MyDate, SizeOf(MyDate));
Read(MyVal, SizeOf(Extended));
Read(MyResult, SizeOf(Extended));
Read(clMyString, SizeOf(Integer));
SetLength(MyString, clMyString));
Read(Pointer(MyString)^, clMyString);
Read(MyBool, SizeOf(Boolean));
Free;
except
Free;
MessageDLG(‚Error reading File‘, mtError, [mbOK], 0);
end;
end;
end;

Für weitere Fragen bin ich ja hier :smile:
Sollte ja ned so schwer verständlich sein

Hallo!

Wenn du die Daten in einem Record hast ohne nullterminierte Strings, ist es wahrscheinlich am einfachsten, eine typisierte Datei zu verwenden:

procedure WriteData(Records: Array of TDatVar);
var f: File of TDatVar; i:integer;
begin
Assign(F,Dateiname);
ReWrite(F);
for i:=low(Records) to High(Records) do Write(f,Records[i]);
CloseGile(F);
end;

procedure ReadData(var Records: Array of TDatVar);
var f: File of TDatVar; i:integer;
begin
Assign(F,Dateiname);
ReSet(F);
i:=0;
While not EOF(f) do begin
Read(f,Records[i]);
inc(i)
end;
CloseGile(F);
end;

Beachte: zum Lesen muß der Speicher für das TDatVar-Array vorher reserviert sein. Wenn die Anzahl der Einträge in der Datei beliebig ist, solltest du mit dynamischen Arrays arbeiten. Noch’n Tip: Du könnstest grundsätzlich das erste Record in der Datei als Header verwenden, wo du keine Feld-Daten speicherst, sondern z.B. Infos über die Versionsnummer und die Anzahl der Datensätze.

Gruß

Jochen

Noch’n Tip: Du könnstest

grundsätzlich das erste Record in der
Datei als Header verwenden, wo du keine
Feld-Daten speicherst, sondern z.B. Infos
über die Versionsnummer und die Anzahl
der Datensätze.

Das nennt man dan Variant-Records…
Funktioniert zwar, aber ist doch alter Turbo Pascal Kinderkram, ich habe mit 16 so programmiert :smile:
Bei dieser Methode verschleuderst einfach jedesmal ein paar Byte, bei einer grossen Datei, bzw. Datenbank kann das durchaus ein Problem werden.

Ich würd nen anständigen Header definieren und eine Body-Struc, dann ist das File auch plattformunabhängig und mit Loader die mit anderen Compiler auch unter anderen Betriebssystemen kompatibel (je nach Datentyp)

Du kannst dich ja am unteren Beispiel orientieren, das ist fast genau gleich.
Du solltest direkt an den Anfang der Datei aber noch einen Header stellen, damit du überhaupt weisst, wieviele Records im File sind. Denn berechnen wie bei Jo’s Version kannst du’s hier nicht, weil diese Methode keine fixen Datenblöcke reserviert sondern immer nur soviel Speicher schreibt und belegt wie nötig. Da du einen String darin hast, ist das variabel.

Das nennt man dan Variant-Records…

Nein, das meine ich nicht.
Das erste Record ist auch vom selben, definierten Typ, nur daß z.B. im ersten Integer-Feld dieses Records z.B. die Anzahl der Records angibt. Dann braucht man kein Body-Struct und durch die Record-Def ist’s eh Plattformunabhängig.

Bei dieser Methode verschleuderst einfach
jedesmal ein paar Byte, bei einer grossen
Datei, bzw. Datenbank kann das durchaus
ein Problem werden.

Jedesmal ? Du hast pro DATEI genau EIN Record mit Infos, die nicht direkt deine Daten sind, sondern ein Header, den du ja auch brauchst:

Ich würd nen anständigen Header
definieren und eine Body-Struc

So what ?

Jochen

Shit ! Falsch gelesen !!!
SORRY !

Du hast ja einen String drin…
MEINE super-einfach-Lösung geht nur bei konstanter Record-Länge (wie ich ja geschrieben habe), also NICHT, wenn nullterminierte Strings drin vorkommen.

WENN Deine Strings aber alle gleich lang sind, kannst du statt String ja z.B. String[20] als Variablendeklaration verwenden. Dann geht’s auch so. Wenn deine Strings länger als 255 Bytes werden, ist das sowieso nicht möglich und wenn sie verschieden lang sein können, verschwendest du mit der fixen Größe Speicherplatz, was bei großen Datenbanken ein Problem sein kann.

Tschö,

Jochen

Habe eure Hinweise und Beispiele gut gebrauchen können und Rogers Variante umgesetzt!