Heute geht es um den Umgang mit Dateien (FILES). dazu gibt es bereits eine standartisierte Bibliothek von entsprechenden Funktionen (zu finden in <stdio.h>). Dazu verwenden wir zum ersten Mal eine Struktur. Eine Struktur ist ein Behälter für verschieden Variablen. Im Beispiel wird folgende Stuktur für alle Dateizugriffe benötigt. Dies ist ein systemabhängiges Beispiel (ATARI ST)
typedef struct
void *BufPtr; /* next byte write */
void *BufLvl; /* next byte read */
void *BufStart; /* first byte of buffer */
void *BufEnd; /* first byte after buffer */
int Handle; /* gemdos handle */
char Flags; /* some Flags */
char resv;
char ChrBuf; /* little buffer */
char ungetFlag;
} FILE;
Das Schlüsselwort =typedef= definiert einen neuen Datentyp.
Syntax: typedef TYP NAME;
In unserem Fall ist der NAME 'FILE'.
Das Schlüsselwort =struct= leitet die Definition der Struktur ein.
Syntax: struct { ELEMENTYP ELEMENTNAME; [ ELEMENTYP ELEMENTNAME ] };
In unserm Fall werden 9 Typen zu einem neuen Typ zusammengefaßt.
Man kann mit der Struktur arbeiten wie mit einer einfachen Variable. Allerdings wird eine Struktur normalerweise immer durch einen Zeiger übergeben. Dies vereinfacht das Programm und reduziert den Speicherbedarf. Auch kann man jederzeit wieder auf die Elemente zugreifen.
FILE *datei_zeiger;
FILE datei;
/* datei_zeiger erhaelt die Adresse von datei */
datei_zeiger = &datei;
/* Ausgabe eines rechnerspezifischen Elemetes */
datei.Handle,
(*datei_zeiger).Handle );
Das Element einer Struktur wird durch anhängen eines Punktes gefolgt vom Elementnamen referenziert. Da sehr häufig Elemente einer Struktur über einen Zeiger angesprochen werde, gibt es in C einen eigenen Operator dafür. Man schreibt: 'datei_zeiger->Handle' statt '(*datei_zeiger).Handle'.
Welchen Vorteil hat dieses Konzept? Wenn man zwei Dateien benutzen will muß man nicht 18 Namen für Variablen definieren, sondern nur zwei. Alle Dateioperationen brauchen nur eine (komplexe Variable) statt 9 Parametern.
Es gibt einige resevierte oder vordefinierte Variablen dieser Struktur.
extern FILE _StdOutF; /* Standard Ausgabe (z.B. Bildschirm) */
extern FILE _StdInF; /* Standard Eingabe (z.B. Tastatur) */
extern FILE _StdErrF; /* Standard Fehler Ausgabe */
extern FILE _StdAuxF; /* Standard Serielle Schnittstelle */
extern FILE _StdPrnF; /* Standard Drucker */
Hier ein Programm zum Ausgeben einer Datei:
CAT.C
Version 1
24.05.92
*/
#include <stdio.h>
#include <stdlib.h>
#define MAXIMALE_ANZAHL_ZEICHEN_PRO_ZEILE 256
/* Speicher fuer eine Zeile aus einer Datei (mit Reserve) */
char buffer[ MAXIMALE_ANZAHL_ZEICHEN_PRO_ZEILE + 1 ];
int anzahl_der_argumente,
char *feld_der_argumente[]
)
int index;
FILE *datei_zeiger;
int fehler;
printf( " Unmoeglicher Fehler, Anzahl <= 0\n" );
exit( 1 );
};
/* Schleife ueber alle Parameter ( Dateinamen ) */
/* nun wird die Variabe durch das Oeffnen der Datei
mit 'fopen' im Textmodus zum lesen ("r") gesetzt */
feld_der_argumente[ index ], "r" );
/* testen ob der Zeiger gueltig ist */
feld_der_argumente[ index ] );
exit( 1 ); /* Programmende */
};
/* innerhalb der Bedingung dieser Schleife wird
geprueft, ob das Ende der Datei erreicht ist.
Dazu wird die Funktion 'feof' aufgerufen.
Die Schleife wird verlassen, wenn das Ende
der Datei erreicht ist. */
/* nun lesen wir eine Zeile ein,
ist eine Zeile laenger als angegeben,
so wird sie abgeschnitten */
MAXIMALE_ANZAHL_ZEICHEN_PRO_ZEILE,
datei_zeiger );
/* pruefe ob ein Fehler aufgetreten ist */
printf( "Lesefehler in Datei %s.\n",
feld_der_argumente[ index ] );
exit( 1 ); /* Programmende */
};
/* ohne Zeilenvorschub ausgeben */
printf( "%s", buffer );
};
/* fertig, Datei schliessen */
fehler = fclose( datei_zeiger );
printf( "Die Datei %s wurde nicht geschlossen.\n",
feld_der_argumente[ index ] );
exit( 1 ); /* Programmende */
}
/* naechsten Parameter berabeiten */
};
/* endlich fertig */
return 0;
}
/* ENDE DER DATEI */
So nun die Aufgabe:
Erweitert das Programm um eine Ausgabe einer Statuszeile am Programmende. Folgende Werte sollen ermittelt werden: