Projekt mit
1 €
unterstützen?
So geht das *:


Step 04 - Filehandling: Basics

 

Wichtige Dateioperationen u.A. im Überblick

 

file Reserviertes Wort. Leitet Typisierung einer Datei ein:
var
  f : file of Byte;
Hierbei wird eine Datei behandelt, die aus einzelnen Bytes besteht.
AssignFile(f: Zeiger auf die Datei; Dateiname: String) Hier wird der Name der Datei festgelegt und an den Zeiger den man mit f typisiert hat, gebunden.
Reset(f: File..) Setzt den Lese-Zeiger an den Anfang zurück. Datei muss existieren.
Rewrite(f: File..) Setzt die Dateigröße auf 0 und erstellt eine Datei, falls sie noch nicht existiert.
Read(f:File..; data) Lest spezifizierte Daten ein. Beim obigen Beispiel wären data einfache Bytes.
Write(f:File..; data) Schreibt Daten in die Datei.
CloseFile(f:File...) Schließt einen offenen Dateizeiger. Geöffnete Dateien können nicht von anderen Programmen geöffnet werden. Daher sollte man Dateien nur so kurz wie möglich öffnen.
eof(f:File...):Boolean = End Of File. Wird meist in While-schleifen benutzt um zu schauen, ob man schon am Ende der Datei angekommen ist. Wichtig hierbei ist das Zurücksetzen (Reset) des Lesezeigers der Datei.
seek(f:File...;l:LongInt); An eine Position innerhalb der Datei springen.
FileExists(FileName : String); Gibt an, ob eine Datei existiert.

Diese Dateioperationen sind auch mit der Arbeit mit Datenströhmen wichtig. Die s.g. Streams können mittels Read/Write/Seek-Methoden quasi wie Dateien behandelt werden.

 

Speichern und Laden von eigenen Dateitypen

 

Zunächst müssen wir hierbei erstmal genau definieren: Was ist eine Datei und was ein Dateityp?

Nun ja, was eine Datei ist dürfte eigentlich jedem klar sein. Eine Datei speichert Daten, die man eingegeben hat, oder Daten die von bestimmten Programmen benötigt werden. Aber auch Programme sind Dateien. Und genau hier setzt der begriff Dateityp an. Programme sind Dateien vom Typ Programm. Es wird auch oft als ausführbare Datei bezeichnet. Diese haben unter Windows beispielsweise die Endungen .exe, .com, .bat und .cmd Die letzteren Zwei, die so genannten Batch-Dateien, sind in Text-form gespeichert und können eigenhändig in einem beliebigen Editor modifiziert werden.

Als Beispiel zu unserem eigenen Dateiformat werden wir nun das Projekt von Step 07 - Arrays und Records weiterentwickeln.

Hierbei ging es bereits um (statische) Arrays und Records um Datenbestände in einer Datei zu speichern. Das ganze sollte nach dem öffnen wie folgt aussehen:

Wir werden es nun folgendermaßen modifizieren:

Zuerst das Äußere:

  • 3 der 4 Eingabeblöcke müssen entfernt werden
  • der nun noch vorhandene Eingabeblock sollte zentriert werden, und bei der Benennung keine Zahlen mehr enthalten (also EdNick1 wird zu EdNick)
  • Die Buttons "Eingabe übernehmen" und "Eingabe anzeigen" links und rechts des Blockes positionieren, den Namen auf BtnPrevious bzw. auf BtnNext und die Aufschrift auf Zurück bzw. Weiter ändern.
  • Ein Label lblPos, welches die aktuelle Position anzeigen soll, wird hinzugefügt und unter dem Eingabeblock positioniert.
  • Ein Weiterer Button BtnNew soll das Hinzufügen von Daten realisieren.

Etwa so sollte es nun aussehen:

Doch bevor es lauffähig wird: Korrektur des Quellcodes:

  • Ein Integer-Feld deklarieren, welches "fCurrentIndex" heisst und bei OnFormCreate auf 0 initialisiert wird.
  • Die Fehlerhaften Zeilen aus BtnLoadFileClick entfernen.
  • Die Methoden BtnSaveArrayClick sowie BtnLoadArrayClick können jetzt geleert werden. Einmal Strg+S und schon sollten die Methoden verschwinden.
Und laufen lassen... ;)

Nun läuft es schonmal, d.h. es hat keine Fehler.
Als nächstes sollen Daten hinzugefügt werden können. Hierzu werden wir erstmal theoretisch-praktisch weitergehen, das heißt ohne Testen, ob einer der folgenden Schritte so stimmt. Zunächst definieren wir den Typ T4ICQContacts zum dynamischen Array um. Da ein Dynamisches Array kein Dateityp sein kann, muss beim Laden und Speichern das "file of T4ICQContacts" zu "file of TICQNmbr" geändert werden. Damit wir es nachher auch gleich ausführen können, geben wir bei Read und Write einen pseudo-Array-Index an, da wir ja mit Read und Write jetzt nur ein Element des Arrays speichern und nichtmehr das ganze Array auf einmal (Bsp: Z. 61: Read(f,ICQNmr[0]); )
Jetzt benennen wir noch unser privates Feld ICQNmr in fICQNmr um und berichtigen mögliche Quelltextfehler falls wir nicht Refactoring benutzt haben. Nun erstellen wir die BtnNewClick-Methode in der folgendes gemacht werden muss:

  • Vergrößern des dynamischen Arrays fICQNmr.
  • fCurrentIndex auf das letzte Element setzen.
  • Momentane Daten im letzten Feld des Arrays speichern.
  • Anzeige berichtigen.
  • BtnSaveFile wieder aktivieren, da ja jetzt Daten zum Speichern vorhanden sind.

Damit hier alle möglichen Fehler beseitigt werden können, hier das Ergebnis:

procedure TMainForm.BtnNewClick(Sender: TObject);
begin
  SetLength(fICQNmr, length(fICQNmr)+1);
  fCurrentIndex := length(fICQNmr)-1;
  fICQNmr[fCurrentIndex].Nick := EdNick.Text;
  fICQNmr[fCurrentIndex].Name := EdName.Text;
  fICQNmr[fCurrentIndex].Surname := EdSurname.Text;
  fICQNmr[fCurrentIndex].UIN := StrToInt(EdUIN.Text);
  lblPos.Caption := IntToStr(fCurrentIndex + 1) + ' / '
                    + IntToStr(length(fICQNmr));
  BtnSaveFile.Enabled := true;
end;

Das Durchscrollen der hiermit erstellten Daten ist genauso einfach. Hierzu müssen wir bei BtnPreviousClick lediglich

  • den Index runterzählen,
  • die entsprechenden Werte aus dem Array in die Felder eintragen,
  • und die Anzeige aktualisieren.

Wir müssen allerdings auch aufpassen, damit nicht außerhalb des Index-bereiches etwas ausgelesen oder geschreiben wird. Der Index-bereich eines dynamischen Arrays geht immer von 0 bis length(Array)-1, jeweils inklusive.

Hier der Beispielcode des Weiter-Buttons (obige Anleitung war für den Zurück-Button!):

procedure TMainForm.BtnNextClick(Sender: TObject);
begin
  if fCurrentIndex < length(fICQNmr)-1 then
    fCurrentIndex := fCurrentIndex+1;
  EdNick.Text := fICQNmr[fCurrentIndex].Nick;
  EdName.Text := fICQNmr[fCurrentIndex].Name;
  EdSurname.Text := fICQNmr[fCurrentIndex].Surname;
  EdUIN.Text := IntToStr(fICQNmr[fCurrentIndex].UIN);
  
  lblPos.Caption := IntToStr(fCurrentIndex + 1) + ' / '
                    + IntToStr(length(fICQNmr));
end;

Somit geht das Scrollen durch die Daten perfekt.

Also kümmern wir uns nun um das Speichern und Laden der Daten.

Beim Speichern müssen wir jedes Record speichern, also das ganze Array durchlaufen. Hier bietet sich eine for-schleife an, welche von 0 bis zum letzten Index-Eintrag von fICQNmr hochzählt und im Schleifenrumpf die Write-Methode ausführt und immer das i-te Element des Arrays in die Datei schreibt. Da wir für Aktualisierungen erstmal einen Button sparen möchten, werden wir beim Speichern den momentan aktiven Datensatz auch gleich im Array aktualisieren. Den Code dazu haben wir ja schon beim Neu-Button.

Das Laden ist etwas komplizierter, da wir nicht wissen, wieviele Elemente in der Datei gespeichert wurden. Es bietet sich also eine While-schleife an.

Damit es beim Laden weniger Schwierigkeiten gibt, hier meine Lösung:

procedure TMainForm.BtnLoadFileClick(Sender: TObject);
var
  f : file of TICQNmbr;
begin
  // falls bereits geladen, Array wieder auf 0 setzen.
  SetLength(fICQNmr, 0);
  // jetzt laden:
  AssignFile(f,'C:\demofile.dat');
  ReSet(f);
  while not eof(f) do
  begin             
    SetLength(fICQNmr, length(fICQNmr)+1);  
    fCurrentIndex := length(fICQNmr)-1;
    Read(f,fICQNmr[fCurrentIndex]);
  end;
  CloseFile(f);
  BtnSaveFile.Enabled:=true;
  // Index auf 0 setzen:
  fCurrentIndex := 0;
  // Datensatz laden:   
  EdNick.Text := fICQNmr[fCurrentIndex].Nick;
  EdName.Text := fICQNmr[fCurrentIndex].Name;
  EdSurname.Text := fICQNmr[fCurrentIndex].Surname;
  EdUIN.Text := IntToStr(fICQNmr[fCurrentIndex].UIN);
  // anzeige
  lblPos.Caption := IntToStr(fCurrentIndex + 1) + ' / '
                    + IntToStr(length(fICQNmr));
end;

Download des kompletten Programmes


Da das Kommentarmodul dieser Seite zur Zeit neu überarbeitet werden muss, sendet bitte alle Fragen, Anregungen oder Probleme mit Betreff zu welchem Thema es sich handelt an folgende Mailadresse:



www.marco-hetzel.de
www.delphi-lernen.de
www.lazarus-lernen.de

© 2006-2019 by Marco Hetzel , last modified 01.11.2018, 11:28

(* Unterstützung dient der Aufrechthaltung laufender Kosten für dieses Projekt.)