Claus SchönleberHitchhacker´s Guide To PASCAL [Vol. 1] |
||
|
[ Start | Beispielprogramme Download | Home ] | |
InhaltCompilerProgrammieren Datentypen, Variablen, Standardfunktionen Logik Verzweigung, Strukturierung Schleifen Felder (Arrays) Verteiler: CASE Zeichenketten (Strings) Textdateien Module (Prozeduren, Funktionen) Anhang (Operatoren, abgeleitete Funktionen)
|
Dateien [1]Die bisher vorgestellten Datenstrukturen sind alle sehr praktisch, solange man es mit Problemlösungen zu tun hat, die mit einer endlichen oder absehbar großen Datenmenge arbeiten. Schwierig wird es dann, wenn man während der Programmierung nicht absehen kann, wieviel Daten man zu verarbeiten hat. Welcher Art diese Problemstellungen sind, soll hier nicht erläutert werden. Wir werden anhand einiger Beispiele ansatzweise klären, wann dieser Fall auftreten kann. Darüberhinaus sei auf weiterführende Literatur verwiesen.Wenn man also mit Verfahren zu tun hat, die es erfordern, daß eine unbekannte Anzahl von Daten bearbeitet werden kann, dann sind die bisher erörterten Strukturen ungeeignet. Eine neue Datenstruktur ist also erforderlich. Eine Aneinanderreihung der zu bearbeiteten Daten bietet sich als einfache Lösung an. Man nennt so eine Folge von Daten Sequenz. Die abstrakte Vorstellung, daß sich einzelne Daten zu einer - theoretisch - unendlichen Folge zusammenfügen lassen, ist in einem Computer natürlich nicht realisierbar, da es sich hier um einen endlichen Automaten handelt. Der Adressraum der Hardware (Arbeitsspeicher) ist begrenzt und kann somit keine unendliche Folge aufnehmen. Wir wollen also den Begriff "unendlich" auffassen als maximale Kapazität des benutzten Adressraums. Das ist trotzdem eine Verbesserung gegenüber den anderen Strukturen, da hiermit eine dynamische Speicherverwaltung möglich wird. Die anderen Strukturen sind statisch, da man vorher festlegen muß, wieviel Daten maximal bearbeitet werden sollen. Die Realisation einer Sequenz geschieht realiter in einer Datei.
Um auf Daten in einer Sequenz zugreifen zu können, kann man mehrere Methoden anwenden. In diesem Kurs wird nur eine Methode, der sequentielle Zugriff (sequential access method), besprochen. Eine Datei, auf die mit dieser Methode zugegriffen wird, heißt Sequentielle Datei. Sequentielle Dateien
Die Daten, die in Dateien zusammengefaßt werden, werden in Datensätzen angeordnet.
Listen wir noch einmal alle Eigenschaften einer Sequentiellen Datei auf:
TextdateienEine besondere Form von sequentiellen Dateien sind die Textdateien. Ein Datensatz einer Textdatei besteht aus einer Zeile aus Zeichen des Zeichensatzes des Computers. Zulässig ist aber nur ein bestimmter Teil des Zeichensatzes, die sogenannten druckbaren Zeichen. Es sind allerdings ein paar Ausnahmen zugelassen; sie werden als Trennzeichen zwischen den Datensätzen und als Dateiendezeichen benutzt.Die Zeilen (Datensätze) einer Textdatei können unterschiedlich
viele Zeichen enthalten (verschieden lang sein). Deswegen ist die
Praktische Anwendung von TextdateienWie legt man nun eine Textdatei an, wie liest man Daten aus ihr oder oder wie schreibt man Daten hinein? Das ermöglichen verschiedene Funktionen oder Prozeduren. Sie werden anhand der einzelnen Arbeitsgänge erläutert.Die Standardprozeduren, die hier verwendet werden, folgen nicht immer dem von Nikolaus Wirth definierten Standard. Insbesondere die Standardprozedur "assign" ist spezifisch für Microcomputerdialekte wie TurboPASCAL. Im Zweifelsfalle wird in diesem Kurs immer die Realisierung dieses Dialektes besprochen, da die Definitionen des PASCAL-Standards für den Alltagsbetrieb nicht ausreichen. Man muß gerade in solchen Fällen in Betracht ziehen, daß PASCAL von Herrn Wirth zunächst ausschließlich als Lehrbeispiel für moderne Programmiertechniken entwickelt wurde. Die Tatsache, daß PASCAL auch in der kommerziellen Welt eine größere Rolle spielte, war nicht wohl nicht geplant, und deswegen fehlen einige Teile im Standard, die man in der Praxis häufig benötigt. Neuanlegen einer TextdateiUm eine Textdatei anzulegen, muß man natürlich erst eine Variable dafür definieren. Denn es ist ja möglich, daß man gleich in mehreren Textdateien arbeiten will, und die müssen ja eindeutig identifizierbar sein.Die Variablen für (Text-)Dateien nennt man Dateivariablen (wie auch sonst!). Als Wert wird ihnen der Name zugewiesen, den die Datei auf der Platte (Diskette oder Festplatte) erhalten soll. Das Problem dabei ist, daß dafür sehr viel mehr Arbeitsgänge erforderlich sind, als bei der Zuweisung einer Konstanten an eine Variable einfachen Typs. Also entfällt die Zuweisung mit ":=". Man hat deswegen eine Standardprozedur eingerichtet, die diese Zuweisung für uns vornimmt. Sie heißt assign (zuweisen): assign (<dateivariable>,<string>) VAR <dateivariable>{,<dateivariable>} : text; Alle weiteren Manipulationen mit der Textdatei werden nur noch über die Dateivariable "workfile" abgewickelt.PROGRAM textdatei_beispiel; VAR workfile : text; filename : STRING [255]; BEGIN write ('Geben Sie den Dateinamen ein: '); readln (filename); assign (workfile,filename); . . . END. Mit der Zuweisung ist aber noch keine Datei auf der Platte eingerichtet. Das besorgt die Standardprozedur "rewrite": rewrite (<dateivariable>); Wir ergänzen unser Beispiel von oben: Damit ist eine Textdatei angelegt.PROGRAM textdatei_beispiel; VAR workfile : text; filename : STRING [255]; BEGIN write ('Geben Sie den Dateinamen ein: '); readln (filename); assign (workfile,filename); rewrite (workfile); . . . END. Schreiben in eine TextdateiUm unsere Datei mit Text zu füllen, bedarf es natürlich irgendwelcher Texteingaben von uns. Für unser Demontrationsbeispiel wollen wir uns darauf beschränken, fünf Namen von der Tastatur zu fordern und sie in die Datei zu schreiben. Dies geschieht mit der gewöhnlichen "writeln"-Prozedur. Sie wird nur um die Angabe der Dateivariablen erweitert:writeln (<dateivariable>,<ausdruck>{,<ausdruck>}); Mit "rewrite" haben wir die Datei zum Schreiben geöffnet, nach der Arbeit müssen wir sie wieder schließen. Das nicht nur aus Symmetriegründen, sondern damit der Puffer geleert wird. Wie oben schon erwähnt, wird der Pufferinhalt erst auf die Platte geschrieben, wenn er voll ist. Am Ende der Bearbeitung kann es aber vorkommen, daß er noch nicht ganz voll ist. Würde man jetzt abbrechen, stünde gar nichts oder nur die unvollständige Datei auf der Platte. Das Schließen der Datei ist also das erzwungene Leeren des Puffers nach getaner Arbeit. Danach wird noch das Inhaltsverzeichnis der Platte auf den neuesten Stand gebracht und der Puffer wieder freigegeben. Die Prozedur, die soviel tut, heißt close:PROGRAM textdatei_beispiel; VAR workfile : text; filename,name : STRING [255]; index : integer; BEGIN write ('Geben Sie den Dateinamen ein: '); readln (filename); assign (workfile,filename); rewrite (workfile); FOR index := 1 TO 5 DO BEGIN write ('Geben Sie den ',index,'. Namen ein: '); readln (name); (*** Jetzt wird in die Datei geschrieben! ***) writeln (workfile,name); END; . . . END. Dieses Programm ist schon vollständig und legt nach der Eingabe von fünf Zeichenketten eine Textdatei mit fünf Datensätzen (Zeilen) an.PROGRAM textdatei_beispiel; VAR workfile : text; filename,name : STRING [255]; index : integer; BEGIN write ('Geben Sie den Dateinamen ein: '); readln (filename); assign (workfile,filename); rewrite (workfile); FOR index := 1 TO 5 DO BEGIN write ('Geben Sie den ',index,'. Namen ein: '); readln (name); (*** Jetzt wird in die Datei geschrieben! ***) writeln (workfile,name); END; close (workfile); END. Die Datei kann jetzt mit jedem Texteditor angesehen werden. Lesen einer TextdateiWir nehmen an, daß das oben stehende Beispiel ausgeführt worden ist. Dann steht auf der Platte eine Datei mit dem von Ihnen ausgewählten Namen. Wenn jetzt wieder auf die Textdatei zugegriffen werden soll, dann brauchen wir eine weitere Standardprozedur; sie soll die Textdatei zum Lesen öffnen. Ihr Name ist "reset". Beim Öffnen geschieht wiederum einiges: Zuerst wird geprüft, ob sich die erwähnte Datei auf der Platte befindet und angesprochen werden kann; dann wird ein Puffer eingerichtet, diesmal für die umgekehrte Richtung; dann wird der Dateizeiger auf den ersten Datensatz (Zeile) der Datei positioniert. Nun kann man Zeilen lesen. Das besorgt die Standardprozedur "readln", die ebenso um die Dateivariable erweitert wird wie die "Kollegin" writeln. Bauen wir also ein Programm, um die Textdatei auszulesen und den Inhalt auf dem Bildschirm aufzulisten:Ich hatte Ihnen natürlich noch etwas verschwiegen; das geschah aber nur deswegen, weil ich Ihnen das jetzt, wo Sie es sehen, besser erklären kann:PROGRAM textdatei_beispiel2; VAR workfile : text; filename,name : STRING [255]; index : integer; BEGIN write ('Geben Sie den Dateinamen ein: '); readln (filename); assign (workfile,filename); reset (workfile); WHILE NOT eof (workfile) DO BEGIN readln (workfile,name); writeln (name); END; close (workfile); END. Da man beim Lesen aus einer (Text-)Datei nicht wissen kann, wieviel Datensätze in ihr enthalten sind, kann in diesem Fall keine Zählschleife benutzt werden. Man muß also die schon vorher erwähnte Systemvariable benutzen, die das Dateiende (Zeichen EOF) anzeigt. Da ja jeder Schreib- oder Lesevorgang den Dateizeiger weiterbewegt, weiß das System immer, wo es ist. Beim Lesevorgang wird darüberhinaus bei jeder Vorwärtsbewegung geprüft, ob der nächste Datensatz nicht gerade das EOF-Zeichen ist. Tritt dieser Fall ein, ändert sich der Zustand der Systemvariablen (sie ist übrigens das Musterbeispiel eines Flags!). Damit wir nicht soviel damit zu tun haben, nehmen uns eine Standardprozedur und eine Standardfunktion die Arbeit ab:
eof (<dateivariable>) Warum benutzt man dann aber eine WHILE-Schleife und nicht REPEAT..UNTIL? Ganz einfach: Eine REPEAT..UNTIL- Schleife prüft die Abbruchbedingung erst nach dem Schleifenblock. Das bedeutet, daß auf jeden Fall zunächst versucht wird, aus der Datei einen Datensatz zu lesen und erst dann wird auf Dateiende geprüft. Ist die Datei aber leer, was oft vorkommen kann, führte das zu einer Fehlermeldung und das Programm bricht ab. Mit der WHILE-Schleife wird die Abbruchbedingung vor dem Eintritt in die Schleife geprüft, was diesen Fehler verhindert. Merksatz: Zum Lesen aus einer Datei benutzt man ausschließlich die WHILE-Schleife in Kombination mit der Standardfunktion "eof".
|
|
|
(c) 2001 Schoenleber.com |