Galileo Computing < openbook > Galileo Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

 << zurück
C von A bis Z von Jürgen Wolf
Das umfassende Handbuch für Linux, Unix und Windows
– 2., aktualisierte und erweiterte Auflage 2006
Buch: C von A bis Z

C von A bis Z
1.116 S., mit CD, Referenzkarte, 39,90 Euro
Galileo Computing
ISBN 3-89842-643-2
gp Kapitel 18 Ein-/Ausgabe-Funktionen
  gp 18.1 Was ist eine Datei?
  gp 18.2 Formatierte und unformatierte Ein-/Ausgabe
  gp 18.3 Streams
  gp 18.4 Höhere Ein-/Ausgabe-Funktionen
  gp 18.5 Datei (Stream) öffnen – fopen
    gp 18.5.1 Modus für fopen()
    gp 18.5.2 Maximale Anzahl geöffneter Dateien – FOPEN_MAX
  gp 18.6 Zeichenweise Lesen und Schreiben – getchar und putchar
    gp 18.6.1 Ein etwas portableres getch()
  gp 18.7 Zeichenweise Lesen und Schreiben – putc/fputc und getc/fgetc
  gp 18.8 Datei (Stream) schließen – fclose
  gp 18.9 Formatiertes Einlesen/Ausgeben von Streams mit fprintf und fscanf
  gp 18.10 Standard-Streams in C
    gp 18.10.1 Standard-Streams umleiten
  gp 18.11 Fehlerbehandlung von Streams – feof, ferror und clearerr
  gp 18.12 Gelesenes Zeichen in die Eingabe zurück-schieben – ungetc
  gp 18.13 (Tastatur-)Puffer leeren – fflush
    gp 18.13.1 Pufferung
  gp 18.14 Stream positionieren – fseek, rewind und ftell
  gp 18.15 Stream positionieren – fsetpos, fgetpos
  gp 18.16 Zeilenweise Ein-/Ausgabe von Streams
    gp 18.16.1 Zeilenweise Lesen mit gets/fgets
    gp 18.16.2 Zeilenweise Schreiben mit puts/fputs
    gp 18.16.3 Zeilenweise Einlesen vom Stream mit getline() (nicht ANSI C)
    gp 18.16.4 Rezepte für zeilenweises Einlesen und Ausgeben
  gp 18.17 Blockweise Lesen und Schreiben – fread und fwrite
    gp 18.17.1 Blockweises Lesen – fread()
    gp 18.17.2 Blockweises Schreiben – fwrite()
    gp 18.17.3 Big-Endian und Little-Endian
  gp 18.18 Datei (Stream) erneut öffnen – freopen
  gp 18.19 Datei löschen oder umbenennen – remove und rename
    gp 18.19.1 remove()
    gp 18.19.2 rename()
  gp 18.20 Pufferung einstellen – setbuf und setvbuf
  gp 18.21 Temporäre Dateien erzeugen – tmpfile und tmpnam
    gp 18.21.1 mkstemp() – Sichere Alternative für Linux/UNIX (nicht ANSI C)
  gp 18.22 Fehlerausgabe mit strerror und perror
  gp 18.23 Formatiert in einem String schreiben und formatiert aus einem String lesen – sscanf und sprintf
  gp 18.24 Fortgeschrittenes Thema
  gp 18.25 Low-Level-Datei-I/O-Funktionen (nicht ANSI C)
  gp 18.26 Datei öffnen – open
  gp 18.27 Datei schließen – close
  gp 18.28 Datei erzeugen – creat
  gp 18.29 Schreiben und Lesen – write und read
  gp 18.30 File-Deskriptor positionieren – lseek
  gp 18.31 File-Deskriptor von einem Stream – fileno
  gp 18.32 Stream von File-Deskriptor – fdopen


Galileo Computing - Zum Seitenanfang

18.5 Datei (Stream) öffnen – fopen  downtop

Die Bearbeitung von Dateien erfolgt in C immer zeichenorientiert. Da Dateien zunächst nichts anderes sind als eine unstrukturierte Folge von Einzelzeichen, spielt es keine Rolle, mit welcher Art von Daten gearbeitet wird. Erst bei der Verarbeitung der Daten bekommen die Einzelzeichen eine Bedeutung und eine Struktur.

Zuerst soll eine einfache Textdatei zum Lesen geöffnet werden. Dabei wird folgendermaßen vorgegangen:

FILE *datei;
...
datei = fopen("textdatei.txt", "r");

Es wurde eine Textdatei mit dem Namen »textdatei.txt« geöffnet. Mithilfe des Zeigers datei vom Typ FILE wird dabei ein Lese-Stream zu dieser Textdatei eingerichtet. Hier die Syntax der Funktion fopen():

#include <stdio.h>
FILE *fopen(const char *pfadname, const char *modus);

Als Pfadangabe (pfadname) ist jeder zulässige String erlaubt. Sollten Sie unter einem Microsoft-Betriebssystem programmieren, kann auch eine Laufwerksangabe erfolgen. Die maximale Stringlänge für pfadname ist in der Konstante FILENAME_MAX, welche sich ebenso in der Headerdatei <stdio.h> befindet, deklariert. Mit modus geben Sie an, wie auf den Stream zugegriffen wird. Im Beispiel wurde der Modus "r" (für read) zum Lesen von der Datei verwendet. Auf die einzelnen möglichen Modi wird gleich eingegangen. Wenn beim Öffnen einer Datei alles planmäßig verlief, wird der FILE-Zeiger zurückgegeben. Bei einem Fehler erhalten Sie hingegen den NULL-Zeiger zurück.

Der FILE-Zeiger – es wird ja auch von einem FILE-Stream gesprochen – ist eine Struktur, die in der Headerdatei <stdio.h> deklariert ist. Diese Struktur beinhaltet alle Informationen, die für die höheren Datei-E/A-Funktionen benötigt werden, beispielsweise:

gp  den Puffer – die Anfangsadresse, den aktuellen Zeiger, die Größe
gp  den File-Deskriptor (mehr dazu bei den Funktionen der niedrigeren Ebene)
gp  die Position von Schreib-oder Lesezeiger
gp  die Fehler- und EOF-Flags

Natürlich können Sie auch mehrere Dateien auf einmal öffnen:

FILE *datei, *datei2;
...
// Datei textdatei.txt zum Lesen öffnen
datei = fopen("textdatei.txt", "r");
// Datei textdat2.txt zum Lesen öffnen
datei2 = fopen("textdat2.txt", "r");

Jetzt zu einem ausführbaren Beispiel der Funktion fopen():

/* fopen1.c */
#include <stdio.h>
#include <stdlib.h>
int main(void) {
   FILE *datei;
   /* Bitte Pfad und Dateinamen anpassen */
   datei = fopen("test.txt", "r");
   if(NULL == datei) {
      printf("Konnte Datei \"test.txt\" nicht öffnen!\n");
      return EXIT_FAILURE;
   }
   return EXIT_SUCCESS;
}

Das Programm öffnet (falls vorhanden) die Datei »test.txt«. Konnte diese Datei nicht geöffnet werden bzw. ist sie nicht vorhanden, dann liefert die Funktion fopen() den NULL-Zeiger zurück. In diesem Beispiel muss sich die Datei »test.txt« im selben Verzeichnis befinden wie das ausführbare Programm. Liegt die Datei »test.txt« hingegen im Verzeichnis

c:\Dokumentationen\Texte\test.txt

dann muss das erste Argument in der Funktion fopen() folgendermaßen aussehen:

datei = fopen("c:\\Dokumentationen\\Texte\\test.txt", "r");

Bei Microsoft-Systemen muss darauf geachtet werden, dass statt nur einem Backslash zwei (\\) geschrieben werden, um das Zeichen '\' anzuzeigen. Bei Linux/UNIX ist das einfacher. Ist das Verzeichnis folgendes

/home/Texte/test.txt

dann muss sich Selbiges im ersten Argument befinden:

datei = fopen("/home/Texte/test.txt", "r");

Unter UNIX/Linux gibt es außerdem keine Laufwerksbezeichnung, da dort jedes Gerät, ob Festplatte, CD/DVD-ROM oder Diskette als Datei betrachtet werden kann.


Hinweis   Bei den meisten Compilern unter MS-Windows kann mittlerweile die Pfadangabe ebenfalls mit einem einfachen Slash (c:/pfad/pfad) – wie bei Linux/UNIX üblich – erfolgen.


Es gibt noch weitere Unterschiede zwischen diesen beiden Betriebssystemen. Hierzu eine Gegenüberstellung von Linux/UNIX und Microsoft-Systemen:


Tabelle 18.2   Systemabhängiges bei Angabe der zu öffnenden Datei

Eigenschaft Linux MS-Windows
Erlaubte Zeichen alle Zeichen Buchstaben, Zahlen und einige Sonderzeichen
Laufwerksbezeichnung A:, b:, c:, … z: keine


Galileo Computing - Zum Seitenanfang

18.5.1 Modus für fopen()  downtop

Außer dem Lesezugriff ("r"), den Sie bereits verwendet haben, gibt es eine Reihe weiterer Zugriffsmöglichkeiten auf einen Stream. Hier ein Überblick über die vorhandenen Modi und deren Bedeutung:


Tabelle 18.3   Modus zum öffnen einer Datei mit fopen()

Modus Bedeutung
"r" Öffnen einer Datei zum Lesen. Wenn die Datei nicht existiert oder nicht geöffnet werden konnte, gibt fopen() NULL zurück.
"w" Anlegen einer Datei zum Ändern. Wenn die Datei nicht geändert werden kann bzw. wenn keine Schreibberechtigung besteht, liefert hier fopen() NULL zurück. Wenn unter Windows/MS-Dos die Datei ein Readonly-Attribut hat, kann diese nicht geöffnet werden.
"a" Öffnet die Datei zum Schreiben oder Anhängen ans Ende der Datei. Wenn die Datei nicht vorhanden ist, liefert fopen() wieder NULL zurück. Auch NULL wird zurückgeliefert, wenn keine Zugriffsrechte bestehen.
"r+" Öffnet die Datei zum Lesen und Schreiben, also zum Verändern. Bei Fehlern oder mangelnden Rechten liefert fopen() auch hier NULL zurück.
"w+" Anlegen einer Datei zum Ändern. Existiert eine Datei mit gleichem Namen, wird diese zuvor gelöscht. Bei Fehlern oder mangelnden Rechten liefert fopen() hier NULL zurück.
"a+" Öffnen einer Datei zum Lesen oder Schreiben am Ende der Datei bzw. die Datei wird angelegt, falls noch nicht vorhanden. Bei Fehlern oder mangelnden Rechten liefert fopen() NULL zurück.

Damit dieses Buch auch als Referenz zu gebrauchen ist, folgt hierzu eine Tabelle für eine schnellere Übersicht der einzelnen Modi:


Tabelle 18.4   Schnellübersicht der Bearbeitungsmodi

Bewirkt r w a r+ w+ a+
Datei ist lesbar x     x x x
Datei ist beschreibbar   x x x x x
Datei ist nur am Dateiende beschreibbar     x     x
Existierender Dateiinhalt geht verloren   x     x  


Hinweis   Wird unter Linux eine neue Datei mit dem Modus "w" oder "a" angelegt, schreibt der POSIX-Standard vor, dass die Datei mit folgenden Rechten angelegt wird: -rw-rw-rw


An diese Modi können außerdem zwei weitere Zeichen angehängt werden, die zwischen Text- und Binärdateien unterscheiden:


Tabelle 18.5   Text- und Binärmodus

Zusätzlicher Modus Bedeutung
b Die Datei wird im Binärmodus geöffnet. Die Zeichen werden dabei nicht verändert bzw. konvertiert. Das heißt, jedes Zeichen wird so weitergegeben, wie es in der Datei steht, und es wird so in die Datei geschrieben, wie die Schreibfunktion eingestellt ist. Der Modus b wird bei Linux nicht verwendet und bei Angabe ignoriert. Er wird nur aus Kompatibilitätsgründen zu ANSI C erhalten.
t Die Datei wird im Textmodus geöffnet und sollte daher auch lesbare Textzeichen beinhalten.

Eine kurze Erklärung des Unterschieds zwischen Textdateien und Binärdateien: Textdateien sind für den Menschen mit einem Editor lesbar. Binärdateien bzw. binäre Zeichen (0,1) bilden die Sprache, die der Computer versteht. Für einen Menschen ist dies kaum lesbar. Daher bestehen Textdateien immer aus sichtbaren ASCII-Zeichen und ein paar Steuercodes, wie etwa Zeilenschaltungen oder Tabulatoren. Für die Bearbeitung reiner Textdateien ist der Modus t gedacht. Da bei MS-DOS ein Zeilenende mit der Sequenz \r\n angezeigt wird und bei Linux nur durch ein einzelnes \n, führen Compiler für MS-DOS/Windows im Textmodus t folgende Konvertierung durch:

gp  Beim Schreiben in eine Textdatei wird ein \n automatisch in ein \r\n konvertiert.
gp  Beim Lesen einer Textdatei wird ein \r\n in ein einzelnes \n konvertiert.
gp  Beim Lesen einer Textdatei wird die Tastenkombination (Strg) + (Z) (unter MS-Windows/DOS) und (Strg) + (D) (unter Linux/UNIX) als Dateiende interpretiert und liefert automatisch EOF (End Of File).

Im Binärmodus wird diese Konvertierung nicht vorgenommen. Bei Linux/UNIX bedeutet das b nichts, wie in der Tabelle oben schon erwähnt, und wird bei Verwendung ignoriert. Unter Linux wird außerdem jede Datei binär gespeichert.

Den Namen der zu öffnenden Datei können Sie natürlich auch mit Hilfe von Argumenten aus der Kommandozeile angeben. Ein Beispiel:

/* fopen2.c */
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
   FILE *datei;
   if(argc < 2) {
      printf("Verwendung : %s [datei_zum_Oeffnen]\n", *argv);
      return EXIT_FAILURE;
   }
   datei = fopen(argv[1], "r");
   if(datei != NULL)
      printf("Datei erfolgreich geöffnet\n");
   else {
      printf("Fehler beim Öffnen der Datei");
      return EXIT_FAILURE;
   }
   return EXIT_SUCCESS;
}

Zuerst wird überprüft, ob zwei Argumente in der Kommandozeile eingegeben wurden. Ist dies nicht der Fall, wird eine entsprechende Fehlermeldung ausgegeben. Ansonsten wird versucht, die Datei, welche Sie in der Kommandozeile mit dem zweiten Argument angegeben haben, zu öffnen. Tritt dabei ein Fehler auf, liegt dies meistens an einer falschen Pfadangabe oder unzureichenden Rechten einer Datei.


Galileo Computing - Zum Seitenanfang

18.5.2 Maximale Anzahl geöffneter Dateien – FOPEN_MAX  toptop

Bei einem Programm, bei dem sehr viele Dateien gleichzeitig geöffnet werden, sollte eine Überprüfung mit der Konstante FOPEN_MAX aus der Headerdatei <stdio.h> vorgenommen werden. Diese Konstante legt fest, wie viele Dateien gleichzeitig pro Prozess geöffnet werden dürfen. Testen können Sie dies z.B. so:

/* fopen3.c */
#include <stdio.h>
#include <stdlib.h>
int main(void) {
   printf("Max. offene Dateien : %d\n",FOPEN_MAX);
   return EXIT_SUCCESS;
}

Hinweis für Fortgeschrittene   Laut ANSI C sollten Sie per fopen() mindestens acht Dateien mit einem Prozess öffnen können.

Meistens liegt dieser Wert aber weitaus höher. Außerdem sind mit acht Dateien reale Streams gemeint, also ohne die Standard-Streams stdin, stdout und stderr. Dies sollte erwähnt werden für den Fall, dass Sie die Struktur FILE tatsächlich auf die Anzahl offener Dateien überprüfen und sich wundern, warum dabei immer mehr Streams offen sind, als Sie in Wirklichkeit geöffnet haben.


Damit alles reibungslos mit dem erfolgreich zurückgegebenen Stream verläuft und Sie problemlos in Dateien schreiben bzw. aus diesen lesen können, müssen Sie bei der Anwendung der Funktion fopen() noch folgende Punkte berücksichtigen:

gp  Fehlerflags und EOF-Flags werden beim Öffnen einer Datei zurückgesetzt.
gp  Wollen Sie, nachdem Sie aus einem Stream gelesen haben, in diesen schreiben, so geht dies nur, wenn Sie vorher eine der folgenden Funktionen verwenden: fflush(), fsetpos(), fseek() oder rewind().
gp  Wollen Sie aus einem Stream lesen, in dem Sie zuvor geschrieben haben, dann müssen Sie eine der Funktionen fsetpos(), fseek() oder rewind() verwenden; außer es wurde das Dateiende (EOF) gelesen.

Falls Sie die Punkte noch nicht verstanden haben, keine Sorge, Sie werden auf den nächsten Seiten aufgeklärt.

 << zurück
  
  Zum Katalog
Zum Katalog: C von A bis Z
C von A bis Z
bestellen
 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchtipps
Zum Katalog: Shell-Programmierung






 Shell-Programmierung


Zum Katalog: Linux-UNIX-Programmierung






 Linux-UNIX-Programmierung


Zum Katalog: C/C++






 C/C++


Zum Katalog: UML 2.0






 UML 2.0


Zum Katalog: Reguläre Ausdrücke






 Reguläre Ausdrücke


Zum Katalog: Linux






 Linux


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo





Copyright © Galileo Press 2006
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Galileo Computing]

Galileo Press, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de