GNU-Pascal in Beispielen: Dateien
zurück zu GNU-Pascal in Beispielen
Dateien
[Bearbeiten]Dateien dienen dazu, Informationen dauerhaft auf Medien zu speichern. In GNU-Pascal wird unterschieden zwischen Textdateien und allgemeinen Dateien, wobei sich dieser Unterschied nur darin zeigt, mit welchen Routinen die Datei gelesen oder beschrieben wird. Das Besondere an Dateivariablen ist, dass man sie einander nicht zuweisen kann.
Aus Textdateien lesen
[Bearbeiten]Das folgende Beispiel zeigt, wie eine Textdatei, in diesem Fall /etc/passwd, ausgelesen wird:
Programm: Lesen
[Bearbeiten]program Lesen;
var
Datei: Text;
Zeile: String (1000);
AnzahlZeilen: Integer = 0;
begin
Assign (Datei, '/etc/passwd');
Reset (Datei);
while not EOF (Datei) do
begin
ReadLn (Datei, Zeile);
WriteLn (Zeile);
Inc (AnzahlZeilen)
end;
Close (Datei);
WriteLn ('Habe ', AnzahlZeilen, ' Zeilen gelesen.')
end.
Erklärung
[Bearbeiten]Der Datentyp Text ist ein Typ für beliebige Textdateien. Mit der Prozedur Assign wird eine namentlich bekannte Datei einer Variablen zugewiesen. Diese Datei kann nun mit Reset zum lesen geöffnet werden. EOF ist eine Funktion, die True ergibt, wenn das Ende der Datei erreicht ist. ReadLn trägt ein Dateiargument, um mitzuteilen, aus welcher Datei eine Datenzeile gelesen werden soll. Mit Close wird die Datei wieder geschlossen.
In Textdateien schreiben
[Bearbeiten]Das folgende Beispiel zeigt, wie in eine Textdatei geschrieben [1] wird:
Programm: Schreiben
[Bearbeiten]program Schreiben;
var
Datei: Text;
Zeile: String (1000);
begin
Assign (Datei, 'namen.text');
Rewrite (Datei);
Write ('Wie lautet ihr Name? ');
ReadLn (Zeile);
WriteLn (Datei, Zeile);
Close (Datei)
end.
Erklärung
[Bearbeiten]In bekannter Weise wird mit Assign ein Dateiname einer Datei zugewiesen. Diese Datei wird mit Rewrite zum Schreiben geöffnet. Eine Textzeile wird mit Hilfe von WriteLn in die Datei geschrieben, wobei auch hier ein zusätzlicher Parameter die Zieldatei angibt.
Vordefinierte Textdateien
[Bearbeiten]Es existieren drei vordefinierte Textdateien, die Standard-Eingabe, Standard-Ausgabe und eine Standard-Fehlerdatei. Die ersten beiden Dateien benutzen sie immer, wenn Sie Texte mit ReadLn einlesen oder mit WriteLn ausgeben. Die dritte Datei muss explizit angesprochen werden:
Programm: Vordef
[Bearbeiten]program Vordef;
begin
WriteLn ('Normale Ausgabe');
WriteLn (StdErr, 'Fehlerausgabe')
end.
Erklärung
[Bearbeiten]Beide Strings werden in unterschiedliche Dateien geschrieben, allerdings merken Sie davon nichts, wenn Sie das Programm nur ausführen. Erst mit vordef 2>/dev/null, wobei Sie die Zwei [2] auch wahlweise durch Eins ersetzen können, ändert sich die Ausgabe. StdErr bezeichnet diesen Fehlerkanal, auf den Sie Fehlermeldungen ausgeben können.
Schreiben und Lesen von allgemeinen Dateien
[Bearbeiten]Das Schreiben und Lesen von allgemeinen Dateien erfolgt analog zum Schreiben und Lesen von Textdateien:
Programm: Allgdatei
[Bearbeiten]program Allgdatei;
var
Datei: File;
i, Wert: Integer;
begin
Assign (Datei, 'werte.dat');
{ Schreiben }
Rewrite (Datei, SizeOf (Integer));
for i := 0 to 10 do
BlockWrite (Datei, i, 1);
Close (Datei);
{ Lesen }
Reset (Datei, SizeOf (Integer));
for i := 0 to 10 do
begin
BlockRead (Datei, Wert, 1);
WriteLn ('Wert = ', Wert)
end;
Close (Datei)
end.
Erklärung
[Bearbeiten]Der Datentyp File ist der Typ einer allgemeinen Datei. Geöffnet wird eine solche Datei zum Schreiben mit Rewrite, wobei als weiterer Parameter die Größe der Daten, die in die Datei geschrieben werden sollen, anzugeben ist. Geschrieben wird in eine solche Datei mit BlockWrite, wobei das erste Argument die Datei ist, das Zweite die Daten und das dritte Argument die Anzahl der Daten, die geschrieben werden sollen, bezeichnet. Reset hat ebenfalls einen zusätzlichen Parameter, der die Blockgröße der zu lesenden Daten angibt. BlockRead liest aus dieser Datei und hat dieselben Argumente wie BlockWrite.
Dateien als Programmparameter
[Bearbeiten]Dateien lassen sich auch im Kopf eines Programms deklarieren. Damit bekommen sie eine Bedeutung, die mit oben erklärten Techniken nicht zu implementieren ist:
Programm: ZeilenZahl
[Bearbeiten]program ZeilenZahl (Input);
var
Zeile: String (1000);
AnzahlZeilen: Integer = 0;
begin
Reset (Input);
while not EOF (Input) do
begin
ReadLn (Input, Zeile);
Inc (AnzahlZeilen)
end;
WriteLn ('Habe ', AnzahlZeilen, ' Zeilen gelesen.');
Close (Input)
end.
Erklärung
[Bearbeiten]Wenn Sie dieses Programm ausführen, so erwartet es Eingaben von Ihnen, bis Sie STRG+D drücken. Viel interessanter ist es aber, das Programm als Filter einzusetzen und durch das Programm hindurchzupipen: cat zeilenzahl.pas | zeilenzahl. Dieses Programm behandelt die ihr übergebenen Textdaten als Datei mit unbekanntem Dateinamen, jedoch bekannter Dateivariablen Input. Diese Datei kann zum Lesen geöffnet werden. Hinter Input dürfen noch weitere Dateivariablen stehen.
Schreiben und Lesen von typbehafteten Dateien
[Bearbeiten]Während man in allgemeine Dateien beliebige Daten ablegen kann und Textdateien zur Speicherung von Text dienen, gibt es in typisierten Dateien die Möglichkeit, eine Menge Daten vom selben Typ abzulegen:
Programm: Typisiert
[Bearbeiten]program Typisiert;
var
Datei: File of Integer;
i: Integer;
begin
Assign (Datei, 'foo.dat');
Rewrite (Datei);
for i := 0 to 10 do
Write (Datei, i);
Close (Datei);
Reset (Datei);
while not EOF (Datei) do
begin
Read (Datei, i);
WriteLn (i)
end;
Close (Datei)
end.
Erklärung
[Bearbeiten]In diesem Beispiel haben wir eine Datei erzeugt, die nur aus Integer-Werten bestehen kann. Dies erreichen wir, indem bei der Variablendeklaration der Datei der zu speichernde Datentyp angegeben wird. In diese Datei kann mit Write geschrieben und mit Read aus ihr gelesen werden. Bei der Verwendung dieser Dateisorte ist es nicht notwendig, Rewrite oder Reset zusätzliche Parameter mitzugeben.
Programmierbeispiel: Adressdatei
[Bearbeiten]Das folgende Programmierbeispiel implementiert eine kleine Adressdatenbank. Sie werden aufgefordert, beliebig viele Adressen einzugeben. Anschließend wird die komplette Datenbank ausgegeben. Als Besonderheit ist das Programm so angelegt, dass die Daten bei einem erneuten Durchlauf nicht verloren gehen, sondern immer weiter angehängt werden:
Programm: Adressedat
[Bearbeiten]program Adressedat;
type
TEintrag = String (30);
TPlz = String (5);
TAdresse = record
Vorname, Name, Strasse: TEintrag;
Plz: TPlz;
Stadt: TEintrag
end;
TAdressDatei = File of TAdresse;
var
Datei: TAdressDatei;
Adresse: TAdresse;
Eingabe: Char;
function FrageAdresse: TAdresse;
var
Anschrift: TAdresse;
begin
with Anschrift do
begin
Write ('Vorname: ');
ReadLn (Vorname);
Write ('Name: ');
ReadLn (Name);
Write ('Strasse: ');
ReadLn (Strasse);
Write ('Postleitzahl: ');
ReadLn (Plz);
Write ('Stadt: ');
ReadLn (Stadt)
end;
FrageAdresse := Anschrift
end;
procedure DruckeAdresse (Anschrift: TAdresse);
begin
with Anschrift do
begin
WriteLn (Vorname, ' ', Name);
WriteLn (Strasse);
WriteLn (Plz, '-', Stadt)
end
end;
procedure SchreibeAdresse (var AdressDatei: TAdressDatei; Anschrift: TAdresse);
begin
Write (AdressDatei, Anschrift)
end;
procedure LiesAdresse (var AdressDatei: TAdressDatei; var Anschrift: TAdresse);
begin
Read (AdressDatei, Anschrift)
end;
begin
Assign (Datei, 'adressen.dat');
Append (Datei);
repeat
Adresse := FrageAdresse;
SchreibeAdresse (Datei, Adresse);
Write ('Eine weitere Adresse eingeben (j/n): ');
ReadLn (Eingabe)
until Eingabe in ['n', 'N'];
Close (Datei);
{ Adressen ausgeben }
WriteLn ('=== Adressen ===');
Assign (Datei, 'adressen.dat');
Reset (Datei);
while not EOF (Datei) do
begin
LiesAdresse (Datei, Adresse);
DruckeAdresse (Adresse)
end;
Close (Datei)
end.
Erklärung
[Bearbeiten]Es wird ein Typ einer typenbehafteten Datei definiert, der in den Funktionen genutzt werden kann. Dateivariablen müssen immer im Original, also Call by Reference, übergeben werden. Die Routine Append öffnet eine Datei zum Anhängen von Daten.
Anmerkungen
[Bearbeiten]- ↑ Bitte beachten Sie, dass diese Datei in Ihrem gewählten Verzeichnis nicht existieren darf, sonst wird sie überschrieben!
- ↑ Hintergrund: 1 bedeutet auf der Shell die Standard-Ausgabe während 2 den Standard-Fehlerkanal bezeichnet. Der Teil 2>/dev/null leitet die Ausgabe des Fehlerkanals so um, dass Sie von der Fehlermeldung nichts zu sehen bekommen. Genauso verfährt man mit der Standard-Eingabe.