9 Arbeiten mit Dateien


9.1 Grundlagen
9.2 Öffnen und Schließen von Dateien
9.3 Datei Ein-/Ausgabe


9.1 Grundlagen

Alle bisher besprochenen Beispiele und Programme waren lediglich in der Lage, von der Standardeingabe (Tastatur) zu lesen bzw. auf die Standardausgabe (Bildschirm) zu schreiben. Unter UNIX (auch unter MS-DOS ab Version 2.0) ist eine Umleitung dieser Standardein-/ausgabe möglich. Die Umleitung bezieht sich auf die Aufrufe der Funktionen getchar, putchar, printf und scanf, also auf alle Funktionen, die von der Standardeingabe (stdin) lesen bzw. auf die Standardausgabe (stdout) schreiben.

Eine Umleitung der Standard Ein-/Ausgabe erfolgt mit den Umleitungssymbolen <, > und >> bzw. durch Pipe Bildung mit | beim Aufruf des Programmes.

Beispiele:


  prog1                 /* prog1 liest von Tastatur und
			   schreibt auf Bildschirm */
  prog1 >hugo           /* prog1 liest von Tastatur und
			   schreibt auf Datei hugo, die neu
			   angelegt wird */
  prog1 <steuer         /* prog1 liest von Datei steuer und
			   schreibt auf Bildschirm */
  prog1 <steuer >>hugo  /* prog1 liest von Datei steuer und
			   schreibt auf Datei hugo weiter */
  prog1 | prog2         /* prog1 liest von Tastatur und gibt
			   Ausgabedaten an prog2 weiter
			   prog2 liest Daten von prog1
			   und schreibt auf Bildschirm */

Die Umleitung erfolgt transparent, d.h. das Programm merkt nichts davon; die Umleitungsangaben tauchen auch nicht in argv auf.

Beim Arbeiten mit Dateien muß die Include-Datei stdio.h dazugeladen werden. Dies erreicht man mittels


  #include <stdio.h>

stdio.h enthält wichtige Definitionen von Konstanten und einer Struktur für den Dateizugriff. (Siehe dazu auch den Eintrag in der C-Standardbibliothek zu stdio.h).


9.2 Öffnen und Schließen von Dateien

Natürlich kann man von einem C Programm aus auch auf jede beliebige Datei zugreifen. Für diese Zugriffe muß die Datei geöffnet und nach Abschluß der Dateiarbeiten wieder geschlossen werden. Zur Identifizierung einer Datei dient dabei ein sogenannter Filepointer, der beim erfolgreichen Öffnen der Datei als Wert der Öffnungsfunktion zurückgegeben wird.

Der Filepointer ist ein Zeiger auf eine Struktur, die Angaben über den Bearbeitungszustand der Datei enthält. Die Einzelheiten dieser Struktur, die in stdio.h definiert ist, sind für uns nicht wichtig. Die Vereinbarungen


  FILE *fp;
  FILE *fopen(char *, char *);

definieren fp als einen Zeiger auf die Struktur FILE und fopen() als eine Funktion, die ein solches Resultat (einen Pointer auf eine Struktur FILE) liefert.

Eine Datei wird dann mittels


  fp = fopen(name, mode);

geöffnet. name ist der Dateiname (genauer Pfadname, Achtung Sonderbedeutung von Backslash in C!) als Zeichenkette und mode kann die Werte "r" (Lesezugriff), "w" (Schreibzugriff) und "a" (anfügender Schreibzugriff) haben. Nach erfolgreichem Öffnen der Datei wird von fopen ein Zeiger auf eine Dateistruktur zurückgeliefert, ansonsten der Wert NULL (wie EOF in stdio.h definiert). War die Datei nicht schon vorhanden, so wird sie angelegt, allerdings nur bei Schreibzugriff (Das Lesen von nicht existierenden Dateien ist natürlich ein Fehler).

Eine geöffnete Datei wird bei Programmende oder -abbruch mit exit() automatisch geschlossen. Dies ist insbesondere bei Schreibzugriffen wichtig, da nur dann der Restpuffer auch wirklich in die Datei gelangt. Generell sollte man aber jede nicht mehr benötigte Datei mit


  fclose(fp);

wieder schließen. fp muß dabei ein vorher von fopen() zurückgebener Filepointer sein.

Die Namen stdin, stdout und stderr sind vordefinierte konstante Filepointer, die man ohne Öffnen der zugehörigen Dateien verwenden kann, da das Öffnen beim Programmstart automatisch besorgt wird. Es gilt folgende Zuordnung:


  stdin   /* Standardeingabe (Tastatur) Umlenkung mit < */
  stdout  /* Standardausgabe (Bildschirm) Umlenkung mit > */
  stderr  /* Fehlerausgabe (Bildschirm) Umlenkung mit 2> */


9.3 Datei Ein-/Ausgabe

Zur zeichenweisen Ein-/Ausgabe von/auf eine Datei, die über einen Filepointer identifiziert wird, stehen die Routinen getc und putc zur Verfügung.


  c = getc(fp);     /* Lesen wie bei getchar */
  putc(c, fp);      /* Schreiben wie bei putchar */

Sonderfall:


  c = getc(stdin);     /* getchar */
  putc(c, stdout);     /* putchar */

Zeilenweise Ein-/Ausgabe kann mittels fgets und fputs erledigt werden.


  fgets(zeile, ZEILAE, fp);

liest die nächste Eingabezeile (bis zum und einschließlich des Zeilenendezeichens) von fp in den Vektor zeile. Es werden maximal ZEILAE-1 Zeichen gelesen und zeile immer mit '\0' abgeschlossen. Funktionswert von fgets ist der Zeigerwert zeile bzw. NULL, wenn das Dateiende erreicht ist (vgl. getline() ).


  fputs(zeile, fp);

schreibt den Inhalt von zeile auf die Datei fp.

Beispielprogramm p9-1.c


  /*
   *      p9-1.c 
   *      Beispielprogramm 1, Abschnitt 9
   *      Realisierung von fgets und fputs 
   */
  
  #include <stdio.h>
  
  /* hoechstens n Zeichen ueber iop einlesen */
  char *fgets(char *s, int n, register FILE *iop)
  {
    register int c;
    register char *cs;
    
    cs = s;
    while (--n > 0 && (c = getc(iop)) != EOF)
      if ((*cs++ = c) == '\n')
	break;
    *cs = '\0';
    return((c == EOF && cs == s) ? NULL : s);
    
  } /* fgets() */
  
  /* Zeichenkette s ueber iop ausgeben */
  void fputs(register char *s, register FILE *iop)
  {
    register int c;
    
    while (c = *s++)
      putc(c, iop);
  
  } /* fputs() */

Beispielprogramm p9-2.c


  /*
   *      p9-2.c 
   *      Beispielprogramm 2, Abschnitt 9
   *      Einfache Realisierung des Kommandos cat
   */
  
  #include <stdio.h>
  
  void filecopy(FILE *);
  
  void main(int argc, char *argv[])
  {
    FILE *fp;
    
    if (argc == 1)        /* ohne Argumente */
      filecopy(stdin);    /* Standard Eingabe kopieren */
    else {
      while (--argc > 0) {
	if ((fp = fopen(*++argv, "r")) == NULL) {
	  fprintf(stderr, "cat: can't open %s\n", *argv);
	  exit(1);
	} 
	else {
	  filecopy(fp);
	  fclose(fp);
	}
      }
    }
    exit(0);
    
  } /* main() */
  
  /* Datei fp als Standard Ausgabe ausgeben */
  void filecopy(register FILE *fp)   
  {
    register int c;
    
    while ((c = getc(fp)) != EOF)
      putc(c, stdout);
      
  } /* filecopy() */

Für die formatierte Datei Ein-/Ausgabe werden fprintf und fscanf verwendet. Sie arbeiten genauso wie printf und scanf, haben jedoch zusätzlich als ersten Parameter den Filepointer fp. Für eine ausführlichere Darstellung der Datei- und der Ein-/Ausgabefunktionen siehe den Abschnitt Ein- und Ausgabe aus der C Standard-Bibliothek.


zurück zum Inhaltsverzeichnis

 

11. November 1999, Peter Klingebiel, DVZ