Einführung in die Programmiersprache Pascal Teil 6

Wie schon im letzten Teil erwähnt, geht es diesmal um den letzten strukturierten Datentyp FILE. Damit ist es möglich, sequentielle Dateien zu erstellen und abzuspeichern. Danach kann man die Daten wieder einlesen und auf dem Bildschirm oder dem Drucker ausgeben.

Anmerkung: Die in diesem Teil des Kurses vorkommenden Programme sind länger als die in den vorangegangenen Teilen. Dies ist jedoch notwendig, wenn man den Umgang mit Dateien an einem sinnvollen Beispiel aufzeigen will. Das Programm SEQ_DAT soll als Gerüst für Ihre eigene Datei dienen, denn es kann durch seinen modularen Aufbau leicht den eigenen Vorstellungen angepaßt und erweitert werden.

Sequentielle Dateien

Eine Datei (FILE) ist eine Folge von Komponenten des gleichen Datentyps. Die Variablenvereinbarung hat die Form: /

Dateivariable : FILE of Datentyp;

Als Datentyp sind prinzipiell alle in Pascal definierten Datentypen erlaubt.

.datei: file of integer;

Damit wird eine Datei definiert, die nur Komponenten vom Typ INTEGER enthalten darf. Der Zugriff auf die einzelnen Komponenten der Datei ist zunächst nur sequentiell möglich. Dies bedeutet, daß man nicht ein beliebiges Element der Datei ansprechen kann, wie dies zum Beispiel bei einem ARRAY möglich ist, indem man den Index angibt. Will man bei einer sequentiellen Datei auf ein bestimmtes Element zugreifen, so muß man alle Komponenten bis zum gewünschten Element einlesen.

Wenn, wie oben beschrieben, ein FILE deklariert wurde, entsteht gleichzeitig eine Zeiger- bzw. Puffervariable:

datei^

Diese Zeigervariable ist kein Teil des FILES. Sie zeigt lediglich auf das aktuelle Element der Datei. Nur mit ihr ist überhaupt ein Zugriff auf die Datei möglich.

Nach der Deklaration enthält eine Datei nur das Zeichen EOF (end of file), also das Dateiendezeichen. Um etwas hineinschreiben zu können, muß man die Datei öffnen:

rewrite(datei,"beispiel")

Wenn nun in eine Datei etwas geschrieben werden soll, dann weist man der Zei^ervariablen einen Wert zu

datei^: = 7

und schreibt diesen mit dem Befehl

put(datei)

in die Datei.

Um Daten aus einer Datei lesen zu können, muß man sie mit dem Befehl

reset(datei,"beispiel")

öffnen. Die Puffervariable datei' hat dann sofort den Wert des ersten Elements der Datei ’beispiel’. Der Wert kann dann auf dem Bildschirm ausgegeben werden:

write(datei^)

Um das nächste Element der Datei ausgeben zu können, muß die Puffervariable um eine Stelle verschoben werden. Dies geschieht mit dem Befehl:

put(datei)

Der jetzige Wert der Puffervariablen kann nun wie oben ausgegeben werden.

Bei den meisten PASCAL-Compilern kann die Anweisungsfolge

datei^ := x;	put(datei)

bzw.

x: = datei^;	get(datei)

ersetzt werden durch

write(datei,x)

bzw.

read(datei,x)

Der Filetyp TEXT

Es gibt einen vordefinierten FILE-Datentyp TEXT. Er ist definiert als:

TEXT : file of char

Textdateien können gegenüber einem FILE OF CHAR mit den Standardprozeduren readln, writeln und eoln bearbeitet werden. Daran läßt sich bereits erkennen, daß dieser Filetyp in Zeilen aufgeteilt ist und deshalb die entsprechenden Befehle auf ihn anwendbar sind.

Textdateien dürfen nur aus den Typen CHAR, INTEGER und REAL bestehen. Die Möglichkeiten zur Bearbeitung von Textdateien sind stark implementierungsabhängig, man sollte deshalb immer das Handbuch zu Rate ziehen, wenn man sich tiefer damit beschäftigen will.

Das Zeilenende wird mit EOLN gekennzeichnet. Wenn EOLN ’true’ wird, dann enthält die Puffervariable ein Leerzeichen.

READLN(datei,Variablenliste) kann so viele Zeichen einiesen, bis das Zeilenende erreicht ist. Die Puffervariable zeigt danach auf die nächste Zeile.

Mit WRITELN(datei,Variablenliste) kann die ganze Variablenliste geschrieben werden. Danach wird ein (systemspezifisch) Zeilenendezeichen EOLN gesetzt.

Programmbeschreibung

Das Programm SEQ__DAT (Listing 1) dient zum Schreiben und Lesen von sequentiellen Dateien. Es besteht im wesentlichen aus vier Prozeduren die vom Hauptprogramm aufgerufen werden. Bei der Variablendeklaration wird eine Variable ’datei’ vom Typ FILE of String festgelegt. Außerdem wird ein Feld eingerichtet, das momentan nur 51 Elemente aufnehmen kann.

Anmerkung: Die Prozedur CLRSCR ist in Turbo-Pascal vorhanden, fehlt jedoch im CCD PASCAL von ATARI.

Die nächste Prozedur ERSTELLEN dient dem Erstellen einer Datei. Sie gibt die Anzahl der geschriebenen Daten in der Variablen nr an das Hauptprogramm zurück.

Es muß zunächst der Name eingegeben werden, unter dem die Datei auf der Diskette abgelegt werden soll. Dieser kann maximal 12 Zeichen enthalten.

Danach folgt die Eröffnung der Datei:

rewrite (datei,dateiname);

Eine Datei gleichen Namens wird dabei unweigerlich gelöscht(!).

Ein Wert wird in die Puffervariable datei^ eingelesen und in die Datei geschrieben, dies geschieht mit den Befehlen:

readln(datei^);
put(datei);

Die Einleseschleife läuft so lange, bis ’★ ’ eingegeben wird. In der Variablen nr ist dann die Anzahl der eingelesenen Daten enthalten.

Die Prozedur LESEN erwartet als erstes den Dateinamen, die entsprechende Datei wird dann geöffnet:

reset(datei,dateiname);

Die erste Abfrage

	if not eof(datei) then...

stellt fest, ob es eine Datei mit dem eingegebenen Namen gibt, und beginnt dann mit dem Einlesen. Hierzu wird eine Schleife verwendet, die so lange läuft, bis das Datenende gefunden wird.

Die eingelesenen Daten werden in ein Feld geschrieben und sind danach immer verfügbar.

Die Prozedur LESEN übergibt die Anzahl der gelesenen Elemente an das Hauptprogr am m.

Die Prozedur AUSGABE benötigt vom Hauptprogramm die Anzahl der Elemente. Sie gibt dann das Datenfeld auf dem Bildschirm aus.

Die letzte Prozedur DRUCKEN gibt die Werte auf dem Drucker aus. Dazu wird mit

rewrite(output,’prn:’)

die Standardfunktion OUTPUT auf den Drucker gelenkt. Dies bedeutet, daß ab dieser Anweisung alle Befehle, die sich sonst auf den Bildschirm beziehen, auf den Drucker ausgegeben werden.

Die Prozedur ruft deshalb nun die Prozedur AUSGABE auf. Auf dem Drucker erscheint dadurch das gleiche Bild wie zuvor auf dem Monitor.

Um die Druckerausgabe zu beenden, lenkt man die Ausgabe wieder auf den Bildschirm

rewrite(output,'con:')

(Diese Befehle gelten in dieser Form für CCD-PASCAL. Bei anderen Compilern muß wegen der abweichenden Syntax im Handbuch nachgeschlagen werden.)

Das Hauptprogramm enthält nur das Menü zur Steuerung der einzelnen Funktionen. Die Funktionen werden mit einem entsprechenden Buchstaben angewählt. Mit einer CASE-Anweisung werden dann die einzelnen Prozeduren aufgerufen und die Parameter übergeben.

Direktzugriffsdatei (random-access)

Die Datei kann bis jetzt nur beschrieben und gelesen werden, ein Hinzufügen oder Ändern von Daten ist nicht vorgesehen. Dies ist zwar prinzipiell auch mit einer sequentiellen Datei möglich, aber sehr umständlich. Die elegantere Methode für diese Aufgaben ist der direkte Zugriff auf eine Datei. Beim CCD-PASCAL ist wahlweise sequentieller und direkter Zugriff möglich, die beiden Formen können sogar gemischt werden. Direktzugriffsdateien sind in STANDARD-PASCAL nicht definiert, jedoch in verschiedenen Pascal-Dialekten bereits vorgesehen (z. B. TURBO-und UCSD-PASCAL). Dabei ist die Syntax der speziellen Befehle z. T. sehr verschieden (bei den oben angegebenen Dialekten wird dafür die Funktion SEEK definiert, die die Puffervariable auf ein beliebiges Element der Datei setzt). Beim CCD-PASCAL ist der Direktzugriff besonders einfach.

Eine Datei besteht aus einer Folge von Elementen, die hintereinander angereiht sind. Durch Angabe der Nummer kann ein Element direkt angesprochen werden. Gegenüber der sequentiellen Methode kommt bei der Syntax lediglich die Angabe der Nummer des Elements hinzu. Geöffnet wird eine Direktzugriffsdatei genauso wie eine sequentielle, mit rewrite bzw. reset. Das Schreiben einer Datei hat dann die Form:

variable^:=x put(variable,nummer)

Gelesen wird die Datei mit:

get(variable,nummer) x:=variable^

Programmodule

Das Programm SEQ_DAT kann mit den Prozeduren VERÄNDERN (List ing 2) und ERWEITERN (Listing 3) ergänzt werden. Diese Prozeduren arbeiten mit direktem Zugriff auf Dateien. Um die Module vom Hauptprogramm aus nutzen zu können, muß, nach ihrem Einfügen im Vereinbarungsteil, der Menüteil erweitert werden. Dies kann dann wie in Listing 4 dargestellt aussehen.

Anmerkung: die Prozedur ERWEITERN muß im Vereinbarungsteil hinter der Prozedur LESEN stehen, weil sie diese auf ruft.

procedure VERAENDERN:
var nr : integer;
begin
	clrscr;
	writeln('VERAENDERN einer Datei'): writeln;
	write ('Dateiname'); readln(dateiname) ; writeln;
	reset(datei,dateiname);
	if not eof(datei) then 
		repeat
			write ('Nummer des Datensatzes: '); readln(nr);
			write ('Inhalt des Datensatzes');
			get(datei,nr);
			writeln(datei^);
			write('neuer Inhalt :	');readln(datei^);
			if datei^<>'*' then put (datei, nr);
		until datei^='*'
	else begin
		write('Datei existiert nicht !'); read(ch)
	end
end; { VERAENDERN }

Listing 2

Struktogramm zu Listing 2
procedure ERWEITERN;
var nr : integer;
begin
	clrscr;
	writeln('ERWEITERN einer Datei'); writeln;
	lesen(nr);	{ ermittelt Anzahl der Daten }
	reset(datei,dateiname);
	writeln;
	if not eof(datei) then
	repeat
		write('Datensatz-Nr ',nr,': '); readln(datei^);
		put(datei,nr);
		nr:=nr+1; 
	until datei^='*'
end; { ERWEITERN }

Unterprogramm ERWEITERN

Variable: nr
	LESEN(nr)
Eingabe: dateiname
Eröffnen der Datei
	Eingabe: datei^
	PUT(datei,nr) 
	nr : =nr + 1
wiederhole bis datei^='*'

Struktogramm zu Listing 3

Die Prozedur VERÄNDERN öffnet die Datei und fragt dann nach der Nummer des Datensatzes, der verändert werden soll. Danach zeigt sie den alten Inhalt an und erwartet die Eingabe des Benutzers. Wenn man ein ’★’ eingibt, wird die Prozedur verlassen.

ERWEITERN ist eine Prozedur, mit der man Daten an eine bestehende Datei anhängen kann. Auch dies ist bei sequentiellen Dateien meistens nicht möglich. Die Prozedur ruft ihrerseits die Prozedur LESEN auf, um die Anzahl der Daten der bereits existierenden Datei zu ermitteln. Danach wird die erste freie Datensatznummer ausgegeben; und das Programm wartet dann auf die Eingabe. Zum Verlassen der Prozedur gibt man ’★’ ein.

Ausklang

Mit diesem Teil ist der Kurs 'Einführung in die Programmiersprache PASCAL’ beendet. Es sind darin alle wesentlichen Befehle und Strukturen dieser Sprache besprochen worden. Natürlich sind die Möglichkeiten, die Pascal bietet, noch wesentlich vielfältiger, sie können jedoch im Rahmen eines Einführungskurses nicht behandelt werden. Ich hoffe, daß Sie mit diesem Kurs soweit in die Sprache eingeführt wurden, um selbst komplexe Programme entwicklen zu können. Sie sollten dabei, besonders bei längeren Programmen, nicht auf die Erstellung eines Struktogramms verzichten, denn diese Technik unterstützt die strukturierte, gut lesbare Programmierung erheblich.

Viel Spaß beim weiteren Programmieren.

(MN)

writeln('Sequentielle & Random-Access DATEI'); writeln;
		.
		.
writeln('Datei Er(W)eitern');
writeln;
writeln(' Daten (V)eraendern') :
		.
		.
case eingabe of
		.
		.
'V',’v' : veraendern;
'W',’w' : erweitern;

Listing 4

# Befehlsübersicht zur Behandlung von Dateien

Auf eine geöffnete Datei läßt sich folgende Funktion anwenden:

EOF(dateivariable): Diese Funktion liefert den Wert ’true’, wenn das Ende einer Datei erreicht wird, ansonsten den Wert ’false’.

Die folgende Prozeduren lassen sich auf Dateien anwenden:

REWRITE(dateivariable,dateiname): Mit diesem Befehl wird eine Datei ’datei-name’ zum Beschreiben geöffnet. Eine eventuell existierende Datei gleichen Namens wird dabei sofort gelöscht(l). Die Zeigervariable ist in diesem Moment noch nicht definiert, eof(variable) ist ’true’.

RESET(dateivariable,dateiname): Dieser Befehl öffnet eine Datei zum Lesen. Die Zeigervariable variable wird auf die erste Komponente des FILES gesetzt und erhält deren Inhalt. Wenn die Datei noch nicht bestand, dann ist die Zeigervariable unbestimmt, eof(variable) erhält den Wert true.

PUT(dateivariable): Durch diesen Befehl wird der aktuelle Wert der Zeigervariable an das momentane Ende des FILES angehängt.

PUT(dateivariable,nummer): Dieser Befehle schreibt den Wert der Zeigervariable in die Datei an die Stelle NUMMER.

GET(dateivariable): Die Zeigervariable wird auf die nächste Komponente gesetzt und erhält deren Inhalt. Wenn diese Komponente nicht existiert, dann ist sie Undefiniert. Wenn es keine weitere Komponente in der Datei gibt, dann wird eof(variable) ’true’.

GET(dateivariable,nummer): Mit diesem Befehl kann ein Element aus der Datei gelesen werden, das an der Stelle NUMMER steht.

CLOSE(dateivariable): Diese Anweisung bewirkt das Schließen einer Datei. Sie ist beim CCD-Pascal jedoch nicht notwendig, weil die Datei automatisch beim Verlesen des Blocks, in dem sie definiert wurde, geschlossen wird.

ERASE(dateivariable): Hiermit kann eine Datei auf der Diskette gelöscht werden. Dieser Befehl ist nur in wenigen Pascal-Versionen implementiert (z. B. TURBO- und CCD-PASCAL)

RENAME(dateivariable1,dateivariable2): Mit dieser Anweisung erhält die Datei 1 den Namen der Datei 2. Dazu müssen beide Dateien geöffnet sein. Danach wird die Datei 2 gelöscht. Dieser Befehl ist in TURBO- und CCD-PASCAL vorhanden.

SEEK(dateivariable,nummer): Damit kann die Puffervariable auf das Element der Datei gesetzt werden, wodurch ein direkter Zugriff auf ein beliebiges Element möglich ist. Der Befehl ist z. B. in TURBO-, UCSD- und CCD-PASCAL vorgesehen.

List of SEQDAT_4.PAS

program SEQ_DATEI(input,output.datei):

{ Lesen und Schreiben von sequentiellen Dateien } 
{ * erstellt mit CCD-Pascal * }

var datei	:	file of string(10);	{ nur	10 Zeichen }
feld	 :	array(0..50)	of	string(10); { nur 50 Elemente }
eingabe,ch:	char;
dateiname :	string(12);
nr,nummer :	integer;

procedure CLRSCR;	{ loescht den Bildschirm }
begin
	write(chr(27), 'E')
end;

procedure ERSTELLEN(var nr: integer):
begin
	clrscr;
	writeln('ERSTELLEN einer Datei'); writeln;
	write('Dateiname : '): readln(dateiname); writeln;
	rewrite(datei,dateiname);	{ kann alte Datei loeschen }
	nr:=—1;
	repeat
		nr:=nr+1;
		write(nr+1,'. ');
		readln(datei^);	{ Zeiger- oder Puffervariable der Datei }
		put(datei);
	until datei^='*';
end;

procedure LESEN(var anzahl; integer);
var nr : integer;
begin
	clrscr;
	writeln('LESEN einer Datei'); writeln;
	write('Dateiname : '); readln(dateiname); writeln;
	reset(datei,dateiname);
	write('LESEN:');
	nr:=-1;
	if not eof(datei) then
		while not eof(datei) do begin
			nr:=nr+1;
			feld[nr]:=datei^;
			get(datei); write('.');
		end
		else begin
			write('Datei existiert nicht !'); read(ch);
			anzahl:=0
		end;
	anzahl:=nr
end;

procedure AUSGABE(anzah1; integer);
var nr : integer;
begin
	clrscr;
	writeln('AUSGABE'); writeln; writeln('DATEI: ',dateiname);
	writeln;
	for nr:=0 to anzahl do
		writeln(nr,'. ‘,feld[nr])
end;

procedure DRUCKEN:
begin
	rewrite(output, 'prn:');	{ siehe Handbuch }
	ausgabe(nr);
	rewrite(output,'con:');
end;

begin { Hauptprogramm }
dateiname:='no name'; nr:=0;
repeat
	clrscr;
	writeln; writeln:
	writeln('Sequentielle DATEI'); writeln;
	writeln('Name der Datei : ',dateiname);
	writeln('Anzahl der Daten : ',nr); writeln;
	writeln('Datei (E)rstellen');
	writeln('Datei (L)esen');
	writeln;
	writeln('Daten (A)usgeben');
	writeln('Daten (D)rucken');writeln;
	writeln('	(*)	—> ENDE');writeln;
	write('Eingabe :	'); read(eingabe)
	case eingabe of
		'A','a' : begin
				if nr>0 then ausgabe(nr)
					else write('keine Daten vorhanden !');
				read(ch);
				end;
		'D','d' : drucken;
		'E','e' : erstellen(nr);
		'L','l' : lesen(nr);
	end;	 { case }
until eingabe='*' { Menueschleife }
end.

Listing 1

Struktogramm zu Listing 1


Aus: ST-Computer 07 / 1986, Seite 62

Links

Copyright-Bestimmungen: siehe Über diese Seite