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.26 Datei öffnen – open  toptop

Öffnen Sie eine Datei mit der Funktion open(), so wird der Datei ein Deskriptor – auch File-Deskriptor genannt – zugeordnet. Ein File-Deskriptor ist eine positive kleine Zahl, die vom Betriebssystem vergeben wird. Über diesen Deskriptor geben Sie an, ob gelesen oder geschrieben werden soll. Mit der Funktion open() kann zudem auch gleich eine Datei angelegt werden. Hier die Syntax mit den dazugehörenden Headerdateien, die mit eingebunden werden müssen, für Linux/UNIX:

#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
int open(const char *pfad, int modus);
int open(const char *pfadname, int flags, mode_t zugriffsrechte);

und die Syntax mit Headerdateien für Windows/MS-DOS:

#include <fcntl.h>
#include <io.h>
#include <sys\stat.h>
int open(const char *pfad, int modus);
int open(const char *pfadname, int flags, mode_t zugriffsrechte);

Als Pfadangabe müssen Sie den absoluten oder relativen Pfad der Datei angeben, die geöffnet werden soll. Da der Prototyp (unter Linux/UNIX zumindest) in Wirklichkeit korrekt open(const char *, int, ...) lautet, kann je nach Situation das dritte Argument auch wegfallen.

Beim Modus gibt es mehrere Varianten, aber diese sind systemabhängig. Einer von den folgenden drei Modi muss immer angegeben werden:


Tabelle 18.11   Bearbeitungsmodi für open()

Modus Bedeutung
O_WRONLY Nur zum Schreiben öffnen
O_RDWR Zum Lesen und Schreiben öffnen
O_RDONLY Nur zum Lesen öffnen

Dies sieht dann bei Linux/UNIX folgendermaßen aus:

int fh;
if((fh = open("/home/programmname", O_RDONLY)) != –1)

oder mit Windows/MS-DOS:

if((fh = open("c:\\config.sys", O_RDONLY)) != –1)

In den beiden Beispielen wird eine Datei nur zum Lesen geöffnet. Zu einem dieser drei genannten Modi können Sie mit dem bitweisen ODER-Zeichen (|) weitere Aktionen verknüpfen. Dies sieht dann so aus:

if((fh = open("c:\\test.sys", O_WRONLY|O_CREAT)) != –1)

Hiermit wird eine Datei zum Schreiben geöffnet. Existiert diese Datei nicht, so wird sie erzeugt (O_CREAT). Existiert diese Datei, so wird der zusätzliche Modus O_CREATE ignoriert. Folgende zusätzliche Modi stehen für Linux/UNIX und Windows/MS-DOS darüber hinaus zur Verfügung:


Tabelle 18.12   Weitere Bearbeitungsmodi für open()

Modus Bedeutung
O_CREAT Falls Datei nicht existiert, wird sie neu angelegt. Falls die Datei existiert, ist O_CREAT ohne Wirkung.
O_APPEND Datei öffnen zum Schreiben am Ende.
O_EXCL O_EXCL kombiniert mit O_CREAT bedeutet, dass die Datei nicht geöffnet werden kann, wenn sie bereits existiert und open() den Wert –1 zurückliefert (-1 == Fehler).
O_TRUNC Datei, die zum Schreiben geöffnet wird, wird geleert. Darauf folgendes Schreiben bewirkt erneutes Beschreiben der Datei von Anfang an. Die Attribute der Datei bleiben erhalten.

Beispielsweise wird mit

if((fh = open("/home/Name.txt", O_WRONLY | O_TRUNC)) != –1)

erreicht, dass die Datei »Name.txt« zum Schreiben geöffnet wird. Der Inhalt dieser Datei wird gelöscht, und sie kann neu beschrieben werden. Weitere Modi, die nur für Linux/UNIX zur Verfügung stehen, sind:


Tabelle 18.13   Bearbeitungsmodi nur für Linux/UNIX

Modus Bedeutung
O_NOCTTY Falls der Pfadname der Name eines Terminals ist, so sollte dieser nicht der neue Kontrollterminal des Prozesses werden, sofern der aktuelle Prozess kein Kontrollterminal besitzt.
O_NONBLOCK Falls der Pfadname der Name eines FIFOs oder einer Gerätedatei ist, wird der Prozess beim Öffnen und bei nachfolgenden I/O-Operationen nicht blockiert. Dieses Flag zeigt seine Wirkung erst bei einer Pipe oder nichtblockierenden Sockets.
O_SYNC Jeder Schreibvorgang auf das Medium wird direkt ausgeführt und es wird gewartet, bis der Schreibvorgang komplett beendet wurde. Dieses Flag setzt den Pufferungsmechanismus außer Kraft. O_SYNC wird nicht von POSIX.1 unterstützt, wohl aber von SVR4.

Für Windows/MS-DOS gibt es folgende extra Modi:


Tabelle 18.14   Bearbeitungsmodi nur für MS-DOS/Windows

Modus Bedeutung
O_BINARY Legt den Binärmodus der Datei fest
O_TEXT Legt den Textmodus der Datei fest

Jetzt folgen noch einige Modi, mit denen die Zugriffsrechte auf eine Datei erteilt werden können. Zuerst für Windows/MS-DOS:


Tabelle 18.15   Zugriffsrechte auf eine Datei erteilen (MS-DOS/Windows)

Modus für Zugriffe Bedeutung
S_IWRITE Schreiben erlaubt
S_IREAD Lesen erlaubt
S_IREAD | SIWRITE Lesen und Schreiben erlaubt

Mit folgender Zeile wird z.B. eine Datei erzeugt, die nur gelesen werden darf:

if((fh=open("new.xxx", O_CREAT , S_IREAD)) == –1)

Wenn Lesen und Schreiben erlaubt sein soll, sieht dies so aus:

if((fh=open("new.xxx",O_CREAT, S_IREAD|S_IWRITE)) == –1)

Diese drei Zugriffsrechte für Windows/MS-DOS stehen in der Headerdatei <sys\stat.h>.

Für Linux/UNIX können Sie folgende Zugriffsrechte erteilen, welche sich in der Headerdatei <sys/stat.h> befinden. Hier die Modi für Zugriffsrechte unter Linux/UNIX:


Tabelle 18.16   Zugriffsrechte auf eine Datei erteilen (Linux/UNIX)

Modus für Zugriffe Bedeutung
S_ISUID set-user-ID Bit
S_ISGID set-group-ID Bit
S_ISVTX sticky Bit (saved-text Bit)
S_IRUSR read (user; Leserecht für Eigentümer)
S_IWUSR write (user; Schreibrecht für Eigentümer)
S_IXUSR execute (user; Ausführungsrecht für Eigentümer)
S_IRWXU read, write, execute (user; Lese-, Schreib-, Ausführungsrecht für Eigentümer)
S_IRGRP read (group; Leserecht für Gruppe)
S_IWGRP write (group; Schreibrecht für Gruppe)
S_IXGRP execute (group; Ausführungsrecht für Gruppe)
S_IRWXG read, write, execute (group; Lese-, Schreib-, Ausführungsrecht für Eigentümer)
S_IROTH read (other; Leserecht für alle anderen Benutzer)
S_IWOTH write (other; Schreibrecht für alle anderen Benutzer)
S_IXOTH execute (other; Ausführungsrecht für alle anderen Benutzer)
S_IRWXO read, write, execute (other; Lese-, Schreib-, Ausführungsrecht für alle anderen Benutzer)


Hinweis   Sofern Sie mit der oktalen Schreibweise der Rechtevergabe vertraut sind, können Sie natürlich diese als Alternative verwenden. Bspw.: fd = open( new_file, O_WRONLY | O_EXCL | O_CREAT, 0644);


Außerdem sollten Sie noch wissen, dass bei Verwendung des Flags O_CREAT die Zugriffsrechte unter Linux/UNIX nicht unbedingt gewährt werden müssen, da die Einschränkungsmaske die Vergabe von Rechten verhindern kann (wird) – und somit die Rechte selbst. Aus diesem Grund wurde mithilfe der Funktion umask() die Maske zur Wegnahme von Rechtebits auf 0 gesetzt, womit alle Zugriffsrechte in dieser Maske erlaubt werden.


Tipp   Standardmäßig wird meistens die Einschränkungsmaske 022 vergeben. Es ist aber auch möglich, mit dem Shell-Builtin-Kommando umask die eigene Einschränkungsmaske zu ändern. Innerhalb eines Listings z.B. würde die neu gesetzte umask von 0 nur während der Ausführung des Programms (und der Unterprozesse) gültig. Dazu kann man bspw. einen entsprechenden umask-Aufruf in einer Startup-Datei wie .profile eintragen, so dass beim Start einer entsprechenden Shell die Einschränkungsmaske automatisch gesetzt wird.


Im folgenden Listing soll eine Datei zum Lesen und Schreiben geöffnet werden. Existiert diese nicht, wird eine neue Datei erzeugt. Falls sie existiert, wird der Inhalt gelöscht und neu beschrieben. Hier der Quellcode, der portabel gehalten wurde:

/* open1.c */
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#ifdef __unix__
      #include <unistd.h>
#elif __MSDOS__ || __WIN32__ || _MSC_VER
      #include <io.h>
#endif
int main(void) {
   int fh;
   if((fh=open("adress.txt", O_RDWR|O_CREAT|O_TRUNC))==-1) {
      perror("Fehler bei open()");
      return EXIT_FAILURE;
   }
   close(fh);
   return EXIT_SUCCESS;
}

Falls Sie jetzt noch die Zugriffsrechte auf diese Datei vergeben wollen, muss für Linux/UNIX die Headerdatei <sys/stat.h> und für MS-DOS/Windows <sys\stat.h> eingebunden werden (beachten Sie den Slash und Backslash). Soll bspw. der User unter Linux diese Datei nur lesen dürfen, so muss nur mithilfe des ODER-Operators der Modus S_IRUSR hinzugefügt werden:

// Alle Zugriffsrechte der Einschränkungsmaske erlauben
umask(0);
open("adress.txt", O_RDWR|O_CREAT|O_TRUNC, S_IRUSR)) == –1)

Ein weiteres Beispiel mit open() ist z.B. das Aufrufen von Programmen aus der Kommandozeile:

/* open2.c */
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#ifdef __unix__
      #include <unistd.h>
      #include <sys/stat.h>
      #include <sys/types.h>
#elif __MSDOS__ || __WIN32__ || _MSC_VER
      #include <io.h>
      #include <sys\stat.h>
#endif
int main(int argc, char **argv) {
   int fh;
   if( (fh=open(*++argv,O_RDONLY)) == –1)
      perror(*argv);
   else
      close(fh);
   return EXIT_SUCCESS;
}

In diesem Beispiel wird eine Datei zum Lesen geöffnet, deren Name als zweites Argument in der Kommandozeile angegeben wurde. Falls die Datei nicht existiert, wird eine entsprechende Fehlermeldung wie

Programmname : No such File in Directory

ausgegeben. Danach wird der File-Deskriptor wieder geschlossen. Falls die Datei, die eben aufgerufen wurde, nicht existiert, aber anschließend erzeugt werden soll, dann ist dies so möglich:

/* open3.c */
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#ifdef __unix__
      #include <unistd.h>
      #include <sys/stat.h>
      #include <sys/types.h>
#elif __MSDOS__ || __WIN32__ || _MSC_VER
      #include <io.h>
      #include <sys\stat.h>
#endif
int main(int argc,char **argv) {
   int fh;
   if(*++argv == NULL)
      return EXIT_FAILURE;  /* Keine Argumente vorhanden */
   if( (fh = open(*argv, O_RDONLY)) == –1)
      if( (fh = open(*argv,O_RDWR|O_CREAT)) == –1)
         perror(*argv);
   close(fh);
   return EXIT_SUCCESS;
}

Hiermit wird zuerst versucht, die Datei zu öffnen. Falls die Datei nicht existiert, wird diese gleich zum Lesen und Schreiben erzeugt.

Bei der Erläuterung der Low-Level-Datei-E/A-Funktionen konnten Sie schon erkennen, warum eher auf die höhere Ebene zurückgegriffen wird. Wer auf mehreren Systemen programmiert, kann schnell durcheinander kommen. Was bei dem einen System gelingt, ist bei dem anderen nicht machbar. Andererseits ist es durchaus hilfreich, beim Erzeugen einer Datei die Zugriffsrechte von Beginn an festzulegen (gilt speziell unter Linux/UNIX). Daraus ergibt sich, dass Low-Level-Datei-E/A vorwiegend zur Systemprogrammierung eingesetzt werden.

Vor allem für Linux/UNIX-Programmierer ist diese Art, eine Datei (auch Gerätedateien) zu öffnen, eine sehr wichtige Schnittstelle. Bspw. kann man hier mit folgendem einfachen Code-Konstrukt etwas auf dem Drucker ausgeben lassen:

int fd;
// Drucker auf /dev/lp0 zum Schreiben öffnen
fd = open("/dev/lp0", O_WRONLY);
if(fd >= 0)
   // Drucken ...
   write(fd, buf, buf_size);
close(fd);
 << 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