Sie sind auf Seite 1von 19

8.

Datei-Eingabe und -Ausgabe


In C sind eine Reihe von Standarddateien
vordefiniert:

ZEIGER GERÄTEDATEI
stdin Standardeingabe
stdout Standardausgabe
stderr Standardfehler-
ausgabe

Diese Standard-FILE-Zeiger sind in jedem C-Programm definiert


und die zugehörigen Gerätedateien werden bei Start geöffnet.

Peter Sobe Informatik I, Sommersem. 2011 1

Zugriffsarten zu Dateien
In C existieren zwei Zugriffsarten:
• High-Level-Zugriff (gepufferte EA)
• Low-Level-Zugriff (ungepufferte EA)
Für jede Zugriffsart steht jeweils eine Menge
bestimmter EA-Funktionen zur Verfügung.
Bei beiden Zugriffsarten stellt die Daten-verwaltung
des Betriebssystems den Inhalt der Datei
unabhängig von der Dateiorganisationsform als
Strom von Zeichen dar.
Der Nutzer kann in C Dateien als Text- oder
Binärdateien betrachten, die bezüglich Steuer-
zeichen unterschiedlich behandelt werden, aber
das Strom von Zeichen – Prinzip gilt bei beiden.
Peter Sobe Informatik I, Sommersem. 2011 2
Zugriffsprinzipien
In C existieren folgende Zugriffsprinzipien:
• zeichenweise E/A (sequentiell)
• zeilenweise E/A (sequentiell)
• formatierte E/A (sequentiell)
• direkte E/A (über direkte Positionierung,
nicht sequentiell)
Für jedes Zugriffsprinzip steht jeweils eine Menge
bestimmter EA-Funktionen zur Verfügung.
Beim formatierten Zugriffsprinzip kann über die
Formatsteuerung im Strom von Zeichen andere Objekte,
wie Zahlen usw. identifiziert und verarbeitet werden.

Peter Sobe Informatik I, Sommersem. 2011 3

Zugriffsmodi beim Öffnen einer Datei


In C bestimmen die Zugriffsmodi, wie eine Datei prinzipiell
zu verarbeiten ist. Die Modi werden bei der Öffnung der
Datei als Zeichenfolge angegeben:
Zugriffsmodus Ziel

„r“ eine bestehende Datei wird zum Lesen


geöffnet. fopen() liefert einen NULL-Zeiger,
wenn Datei nicht existiert oder nicht
gefunden wird (Pfad!)
„w“ Datei zum Schreiben öffnen. Die Datei
wird erzeugt, wenn sie noch nicht
existiert. Existiert die Datei, wird der
alte Inhalt überschrieben.
Peter Sobe Informatik I, Sommersem. 2011 4
Zugriffsmodi (Fortsetzung)
Zugriffsmodus Ziel

„a“ Datei zum Anfügen öffnen, d.h. es


wird am Dateiende weiter geschrieben.
Die Datei wird erzeugt, wenn sie noch
nicht existiert .
„r+“ Bestehende Datei zum Lesen und
Schreiben öffnen. fopen() liefert den
NULL-Zeiger zurück, wenn sie nicht
existiert.
„w+“ Bestehende Datei zum Schreiben und
Lesen öffnen. Existiert die Datei, wird
ihr Inhalt überschrieben.

Peter Sobe Informatik I, Sommersem. 2011 5

Zugriffsmodi (Fortsetzung)
Zugriffsmodus Ziel

„a+“ Die Datei wird zum Lesen und Anfügen


geöffnet. Die Datei wird erzeugt, wenn
sie nicht existiert .
Zusatzangabe zur Unterscheidung von Dateiarten:
t Datei wird als Text- (ASCII-) Datei
betrachtet. t ist Standard und kann
weggelassen werden.
b Datei wird als Binär- Datei
betrachtet.
Die Zusatzangabe wird dem Zugriffsmodus hinzu-
gefügt, z.B. „rt“, „wb“ , „at+“, „rb+“ usw.
Peter Sobe Informatik I, Sommersem. 2011 6
Text- und Binär-Dateien
Fehlt die Zusatzangabe zur Unterscheidung von Dateiarten
so wird standardmäßig t für Text- (ASCII-) Datei
angenommen.
Der Unterschied zwischen Text- und Binärdateien besteht in
der Behandlung des Zeilenendes.
Wird eine Datei als Textdatei geöffnet, wird das Zeilenende
nur durch das Zeichen
Linefeed \n ASCII-Wert 10 dargestellt.
Wird eine Datei als Binärdatei geöffnet, wird das Zeilenende
durch zwei Zeichen CariageReturn+Linefeed \r\n ASCII-
Wert 13+10 dargestellt.
Damit hat die Datei eine unterschiedliche Länge!
Peter Sobe Informatik I, Sommersem. 2011 7

High-Level-Zugriff zu Dateien
FILE-Struktur
Zeiger auf
Puffer

Zeiger auf
nächstes
Zeichen im
Puffer
Anzahl
Zeichen im
Puffer

Deskriptor

Daten schreiben Daten schreiben

FILE-Zeiger

Programm Daten lesen Puffer Daten lesen Datei

Peter Sobe Informatik I, Sommersem. 2011 8


High-Level-Zugriff: Öffnen und Schließen
In C wird eine Datei mit fopen bzw. fclose geöffnet bzw.
wieder geschlossen. Dabei muss der FILE-
Zeiger deklariert sein:

#include <stdio.h>
void main()
{
FILE *fp; //Deklaration File-Zeiger
fp = fopen(„c:\\meinefreunde.txt“,“r“); //Pfad-Angabe
...........
fclose(fp);
}
Kann die Datei nicht geöffnet werden, ist fp mit NULL belegt.
Deshalb sollte nach fopen der Dateizeiger auf NULL getestet
werden, ehe eine Verarbeitung eingeleitet wird.
Peter Sobe Informatik I, Sommersem. 2011 9

Öffnen und Schließen einer Datei


Die Funktion fopen erfordert für Datei- und Ordner-
namen die Einhaltung der Konventionen für Dateinamen
Die Funktion fclose erzeugt bei erfolgreichem Schließen
der Datei den Rückkehrwert 0, sonst einen Fehlerkode.
fclose erzeugt automatisch das Dateiendezeichen
EOF ASCII-Wert -1
und schreibt es als letztes Zeichen in die Datei.

Peter Sobe Informatik I, Sommersem. 2011 10


High-Level-Zugriff: Zeichenweises Lesen
In C wird mit fgetc eine Datei zeichenweise gelesen:

#include <stdio.h>
void main()
{ char c; FILE *fp;
fp = fopen(„c:\\dat.txt“,“r“);
if (fp!=NULL)
{ c=fgetc(fp); //Lesen nächstes Zeichen
if (c==EOF) ... //Prüfen auf EndOfFile

fclose(fp);
}
Nach jeder Leseoperation sollte auf das Erreichen des
Dateiendes (EOF) getestet werden.

Peter Sobe Informatik I, Sommersem. 2011 11

High-Level-Zugriff: Zeichenweises Lesen


Typischerweise kann man in C-Programmen beim
zeichenweisen Lesen und Verarbeiten einer Datei eine nicht-
abweisende Schleife verwenden:

#include <stdio.h>
void main()
{ char c; FILE *fp; fp = fopen(„c:\\dat.txt“,“r“);
if (fp!=NULL)
{ do {
c=fgetc(fp); //Lesen nächstes Zeichen
...... Verarbeitungsanweisungen
} while (c!=EOF) ; //Prüfen auf End Of File
}
if ( ! fclose(fp)) // ungleich 0 -> Erfolg
printf(„Datei erfolgreich geschlossen“);
}
Peter Sobe Informatik I, Sommersem. 2011 12
High-Level-Zugriff: Zeichenweises Schreiben
In C wird mit fputc eine Datei zeichenweise geschrieben:

#include <stdio.h>
void main()
{
char c; FILE *fp;
fp = fopen(„c:\\dat.txt“,“w“);
c=‚A‘;
fputc(c,fp); //Schreiben Zeichen c
...........
fclose(fp); // EOF-Zeichen wird gesetzt
}

Peter Sobe Informatik I, Sommersem. 2011 13

High-Level-Zugriff: Zeilenweises Lesen


In C wird mit fgets eine Datei zeilenweise gelesen.
Dabei muss im Programm ein Pufferspeicher als char-Feld
vereinbart werden, der die eingelesene Zeile aufnimmt.

Es ist zweckmäßig einen char-Zeiger zu deklarieren,


der durch fgets belegt wird und auf den Anfang des Puffers
zeigt bzw. auf NULL im Fehlerfall oder bei Erreichen des
Dateiendes (EOF).
char puffer[81]; char *z; FILE *fp;
z=fgets(puffer,81,fp); //Lesen Zeile

Peter Sobe Informatik I, Sommersem. 2011 14


High-Level-Zugriff: Zeilenweises Lesen
Die Funktion fgets arbeitet dabei folgendermaßen:
z=fgets(puffer,81,fp); //Lesen Zeile
1. fgets liest eine Zeile bis zum Zeichen ‘ \n‘ , falls
dieses bis zum 80. Zeichen gefunden wurde.
Diese max. 80 gelesenen Zeichen werden in den
Puffer geschrieben, einschließlich ‘ \n‘ . Dahinter
wird ein string-Abschluss ‘ \0‘ geschrieben, damit
die Zeile als string verarbeitet werden kann.
Der Zeiger z wird auf die puffer–Adresse gesetzt.
2. fgets beendet nach der im 2.Argument angegebe-
nen Zeichenzahl (-1), falls bis dahin das ‘ \n‘ – Zeichen nicht
gefunden wurde. Das letzte Zeichen
wird für das Schreiben des ‘ \0‘ –Zeichens benötigt.

Peter Sobe Informatik I, Sommersem. 2011 15

High-Level-Zugriff: Zeilenweises Lesen


3. fgets liest eine Zeile bis zum Dateiende-Zeichen EOF,
falls dieses vor Erreichen des 80.Zeichens
bzw. und ohne Finden eines ‘ \n‘ erreicht wurde.
Diese verbleibenden Rest-Zeichen werden in den
Puffer geschrieben, einschließlich ‘ \n‘ . Dahinter
wird ein string-Abschluss ‘ \0‘ geschrieben, damit
die Zeile als string verarbeitbar ist.
4. Kann nichts mehr gelesen werden, wird der Zeiger z
auf die NULL–Adresse gesetzt.
Die NULL-Adresse wird auch bei einem Lesefehler
zurückgegeben. Über die Funktion ferror lässt sich ein
Fehler oder EOF abklären.
Vorführung: File_2.c
Peter Sobe Informatik I, Sommersem. 2011 16
High-Level-Zugriff: Zeilenweises Schreiben
In C wird mit fputs eine Datei zeilenweise geschrieben:

#include <stdio.h>
void main()
{ char c; FILE *fp;
char zeile[81]=„Das ist eine Zeile!“;
char *z=zeile;
fp = fopen(“c:\\dat.txt“,“w“);
fputs(z, fp); //Schreiben Zeile
...........
fclose(fp); // EOF wird gesetzt
}

Peter Sobe Informatik I, Sommersem. 2011 17

Formatiertes Lesen einer Datei


In C wird mit fscanf eine Datei formatiert gelesen:

#include <stdio.h>
void main()
{ char c; FILE *fp; int ao;
struct abt{char nr[5]; char nam[20]; char leit[7];} a;
fp = fopen(„c:\\dat.txt“,“r“);
ao=fscanf(fp,“%s%s%s“, a.nr,a.nam,a.leit);
//Lesen Anzahl von Objekten nr,nam,leit
// Rückkehrwert ao ist die Anzahl gelesener Obj.
// Rueckkehrwert –1 bei EOF
...........
fclose(fp); // EOF wird gesetzt
}
Peter Sobe Informatik I, Sommersem. 2011 18
Formatiertes Schreiben einer Datei
In C wird mit fprintf eine Datei formatiert geschrieben:
#include <stdio.h>
void main()
{ char c; FILE *fp; int ao;
struct abt{char nr[5]; char nam[20]; char leit[7];}
a={„111“,“Produktion“,“4531“};
fp = fopen(„c:\\dat.txt“,“w“);
ao=fprintf(fp,“%s%s%s“, a.nr,a.nam,a.leit);
//Schreiben von Objekten nr,nam,leit
// Rückkehrwert ao ist die Anzahl geschriebener Obj.
// Rueckkehrwert –1 bei EOF
...........
fclose(fp); // EOF wird gesetzt
}
Peter Sobe Informatik I, Sommersem. 2011 19

Verschiedene Funktionen für die Dateiarbeit

In C werden für Hilfszwecke rund um die Datei-


Verarbeitung eine Reihe von Funktionen angeboten:

Das sind vor allem Funktionen für


• die Arbeit mit Verzeichnissen und Laufwerken
• das Umbenennen und Löschen von Dateien/Ordnern
• das Positionieren des Dateizeigers und
• die Fehlerbehandlung

Peter Sobe Informatik I, Sommersem. 2011 20


Funktionen für die Arbeit mit Verzeichnissen (1)
Das aktuelle Laufwerk kann man mit der Funktion
void _dos_getdrive(unsigned *lw)
ermitteln.

Beispiel:
unsigned d;
_dos_getdrive(&d); //ermittelt aktuelles LW
printf("Das aktuelle LW ist: %c\n", d + 'A' - 1);

Es wird die aktuelle Laufwerks-Nummer zurückgegeben,


A=1, B=2, C=3,...
Nur in Windows möglich!
Demonstration mit
Andere Betriebssysteme
Programm file_drive.c benutzen keine
Laufwerke.
Peter Sobe Informatik I, Sommersem. 2011 21

Funktionen für die Arbeit mit Verzeichnissen (2)

Das aktuelle Laufwerk kann man mit der Funktion


void _dos_setdrive(unsigned lw,unsigned *anz)
neu gesetzt werden.

Beispiel:
unsigned n;
_dos_setdrive(3,&n); //setzt aktuelles LW auf C
printf(„Es gibt insgesamt %d LW \n",n);

Es wird die max. Anzahl von logischen LW-Nummern


zurückgegeben.

Vgl. Programm file_drive.c

Informatik I, Sommersem. 2011 22


Peter Sobe
Funktionen für die Arbeit mit Verzeichnissen (3)

UNIX-Dateisysteme (POSIX Standard)


Ermitteln des aktuellen Arbeitsverzeichnisses:
char *getcwd(char *buf, size_t size);
Schreibt das aktuell eingenommene Verzeichnis in die
Zeichenkette buf mit maximal size Zeichen.
Bei Erfolg wird der Zeiger buf zurückgegeben,
anderenfalls NULL. Die Variable errno zeigt den Grund
des Fehlers an, z.B. ERANGE wenn size zu kurz ist.
Setzen:
int chdir(const char *pfad); // gibt 0 bei Erfolg zurück

Informatik I, Sommersem. 2011 23


Peter Sobe

Durchlaufen von Verzeichnissen

Mit den Funktionen


unsigned _findfirst(const char *pfad, struct _finddata_t *fblk)
und
unsigned _findnext( struct _finddata_t *fblk)
kann der Inhalt eines Verzeichnisses schrittweise gelesen
werden.
Der pfad-Parameter ist die Adresse eines Pfades (z.B.
c:\temp) ..), der Parameter fblk ist die Adresse einer
Strukturvariablen, die dann die Resultate enthält (z.B.Namen
der Datei, Größe in Bytes, Änderungsdatum und –zeit).

Peter Sobe Informatik I, Sommersem. 2011 24


Durchlaufen von Verzeichnissen
Beispiel:

_finddata_t filesfound;
intptr_t f = _findfirst("C:\\TEMP\\*.*",&filesfound);
//Alle Dateien in C:\TEMP
if ( f != -1L ) {
do {
if ( !( filesfound.attrib & _A_SUBDIR ) )
{ //Verzeichnis ausschliessen
printf("%s %Iu\n",filesfound.name,filesfound.size);
}
} while ( _findnext(f,&filesfound)==0 ); //Nächste Datei
_findclose(f); //Handle schliessen
}

Informatik I, Sommersem. 2011 25


Peter Sobe

Funktionen für die Arbeit mit Verzeichnissen


Das Anlegen (Erzeugen) eines Ordners erfolgt mit der C-
Funktion
int mkdir(cont char *pfad).

Bei fehlerfreier Ausführung ist der Rückkehrwert 0, sonst –1.

char pfad[30]=„c:\\temp\\neu“;
if (mkdir(pfad))
printf(„\nFehler!“);
else
printf(„\nOrdner erfolgreich erzeugt“);

Informatik I, Sommersem. 2011 26


Peter Sobe
Umbenennen und Löschen von Dateien/Ordnern
Das Umbenennen einer Datei/ eines Ordners erfolgt mit der C-
Funktion
int rename(const char *alt, const char *neu).

Die Parameter alt und neu können vollständige Pfadangaben


enthalten. Beide Pfade müssen gleich sein. Der Zugriff auf die
Datei/Ordner muss nach Zugriffsrechten erlaubt sein.
Bei fehlerfreier Ausführung ist der Rückkehrwert 0, sonst –1.

char a[20]=„c:\\temp\\x.txt“;
char n[20]=„c:\\temp\\y.txt“;
// bei einem Ordner „texte“ würde der Pfad z.B. sein
// char a[20]=„c:\\temp\\texte“;
if (! rename(a,n)) printf(„\nFehler!“);

Peter Sobe Informatik I, Sommersem. 2011 27

Löschen von Dateien/Ordnern


Das Löschen einer Datei erfolgt mit der C-Funktion
int remove(const char *name).

Gesperrte Dateien:
Die im Parameter angegebene Datei darf zu diesem
Zeitpunkt nicht in Nutzung sein, d.h. muss geschlossen
sein. Bei fehlerfreier Ausführung ist der Rückkehrwert 0,
sonst –1.

char datei[20]=„c:\\temp\\x.txt“;
if (! remove(datei)) printf(„\nFehler!“);
else printf(„\nDatei erfolgreich gelöscht“);

Peter Sobe Informatik I, Sommersem. 2011 28


Löschen von Dateien/Ordnern
Das Löschen eines Ordners erfolgt mit der C-Funktion
int rmdir(const char *name).

Der im Parameter angegebene Ordner muss zu diesem


Zeitpunkt leer sein, er darf nicht das aktuelle
Arbeitsverzeichnis sein und nicht das Stammverzeichnis
des LW. Bei fehlerfreier Ausführung ist der Rückkehrwert
0, sonst –1.

char ordner[20]=„c:\\temp\\texte“;
if (! rmdir(ordner)) printf(„\nFehler!“);
else printf(„\nOrdner erfolgreich gelöscht“);

Peter Sobe Informatik I, Sommersem. 2011 29

Positionieren in Dateien
Die wichtigste Positionieroperation ist das Zurück-setzen einer
Datei an den Anfang: void rewind(FILE *fz);

fz ist dabei der FILE-Zeiger. rewind gibt bei Ausführung keinen


Rückkehrwert an.

Mit der Positionieroperation: (nur im Binärmodus)


int fseek(FILE *fz, long anz, int pos_mode);

Der Parameter anz gibt die Anzahl der Bytes relativ zu pos_mode
an, um die der Dateizeiger bewegt werden soll. Für pos_mode
gibt es nur drei Möglichkeiten:
0 für Dateianfang (Konstante SEEK_SET),
1 für aktuelle Position (Konstante SEEK_CURR) und
2 für Dateiende (SEEK_END).
Bei fehlerfreier Ausführung ist der Rückkehrw. 0, sonst ungleich 0.
Informatik I, Sommersem. 2011 30
Peter Sobe
Positionieren in Dateien
Beispiel:
fseek(fz, -10L, 1);

Der Dateizeiger der Datei fz wird ab der aktuellen


Zeigerposition 1 um insgesamt 10 Bytes zurückgesetzt.

Mit der Funktion


long ftell(FILE *fz)
wird der aktuelle Dateizeiger der Datei fz relativ zum
Dateianfang (als Anzahl der Bytes ) zurückgegeben.
ftell sollte wegen der unterschiedlichen Darstellung des
Zeilenendes nur im Binärmodus verwendet werden.

Informatik I, Sommersem. 2011 31


Peter Sobe

Low-Level Verarbeitung von Dateien


Eine Datei wird mit der Funktion
int open(const char *path,int access, int mode)

geöffnet. path ist dabei der Pfad- und Dateiname. Mit access werden
Zugriffsflags angegeben. Mit dem bit-weisen ODER können
folgende Konstanten gesetzt sein:

O_APPEND neu geschriebene Daten werden angehängt


O_CREAT wenn die Datei nicht existiert, wird sie mit
dem im Parameter mode angegebenen
Eigenschaften erzeugt
O_TRUNC wenn die Datei existiert, wird der Inhalt überschrieben
O_BINARY und O_TEXT sind zusätzlich möglich

Den Parameter mode setzt Zugriffsrechte (insgesamt 9 Bits).


Peter Sobe Informatik I, Sommersem. 2011 32
Low-Level Verarbeitung von Dateien
Zugriffsrechte:
Flags Lesen (r ), Schreiben (w) und Ausführen (x) für den
Eigentümer (u - user), für die Gruppe (g - group) und für den
Rest (o – others).
Kodierung in 9-Bits:
user group others
rwx–rwx–rwx
Beispiel:
111 100 000
bedeutet, dass der Eigentümer alles darf, die Nutzer in der
gleichen Gruppe dürfen die Datei zum Lesen öffnen.
Zugriffsrechte werden oft durch Oktalzahlen angeben.
Eine Stelle fasst 3 Bits zusammen. Im Beispiel ergibt sich 740.

Informatik I, Sommersem. 2011 33


Peter Sobe

Low-Level Verarbeitung: Öffnen

open liefert den Dateideskriptor, eine Zahl, zurück.


Beispiel:
outfile = open(pfad, O_WRONLY | O_CREAT |
O_TRUNC, 0777)
Die Oktalzahl O777 setzt alle Zugriffsrechte.
Der übergebene Dateideskriptor (hier outfile) ist eine
natürliche Zahl ab 5 und bildet den Rückkehrwert von
open. Die Werte 0..4 sind reserviert für 0 stdin, 1 stdout, 2
stderror, 3 stdaux, 4 stdprn.

Ein Rückkehrwert von –1 signalisiert einen Fehler.


Peter Sobe Informatik I, Sommersem. 2011 34
Low-Level Verarbeitung: Close und Read
Eine Datei wird mit der Funktion
int close(int file_access)
geschlossen. Für den Parameter file_access tritt dann der
Deskriptor, d.h. z.B. fileout=5. Ein Rückkehrwert von 0 ist in
Ordnung. Ein Wert –1 signalisiert einen Fehler.

Das Lesen einer Bytefolge mit der Länge len von der Datei
mit dem Deskriptor file_descriptor wird mit der Funktion
int read(int file_descriptor, void buf, unsigned len)
ausgeführt, wobei die Bytefolge in den Hauptspeicher ab
der Adresse buf geschrieben wird. Der Rückkehrwert von
read ist die Anzahl der gelesenen Bytes:
nbytes = read(infile, rwbuf, 1024)
Im Fehlerfall ist der Rückkehr Wert –1.

Peter Sobe Informatik I, Sommersem. 2011 35

Low-Level Verarbeitung: Write

Das Schreiben einer Bytefolge der Länge len wird mit der
Funktion
int write(int file_descriptor, void buf, unsigned len)
aufgerufen, wobei int file_descriptor das Handle auf die
Ausgabe-Datei darstellt (Dateideskriptor). Die zu
schreibende die Bytefolge wird dem Hauptspeicher ab der
Adresse buf entnommen. Der Rückkehrwert von write ist
die tatsächlich geschriebene Anzahl der Bytes.
Beispiel:
int wlen = write(outfile, wbuf, 1024) ;

Im Fehlerfall ist der Rückkehrwert –1.

Informatik I, Sommersem. 2011 36


Peter Sobe
Low-Level Verarbeitung: Write

Beispiel:

Das Schreiben einer Fehlermeldung errmsg in die Datei


stderr wird mit dem Aufruf

write(2, errmsg, strlen(errmsg));

durchgeführt, wobei errmsg wie folgt deklariert ist:


char *errmsg ="\nDatei konnte nicht geoeffnet werden.";

Peter Sobe Informatik I, Sommersem. 2011 37

Das könnte Ihnen auch gefallen