ein Kapitel zurück                                           ein Kapitel weiter

Bevor ich zur Low-Level-Funktion open komme möchte ich noch ein paar Zeilen zum Low-Level-Datei-I/O verlieren :

Mit High-Level greifen sie auf Daten in einem hohen Abstraktionsniveau zu. Das heißt die Daten eines Programms werden formatiert ausgegeben oder eingelesen. Mit Low-Level arbeiten sie in einem tierfern Niveau. Und das heißt genauer das auf die Daten lediglich zugegriffen wird als Folge von unstrukturierten Bytes und bietet die Möglichkeiten, Bytesequenzen vorgegebener Länge einzulesen oder auszugeben. Die Ähnlichkeit der Funktionsnamen in Low-Level zu High-Level sind auch von der Abarbeitung ähnlich, nur mit einem aber sehr prinzipiellen Unterschied der etwas Verwirrend ist. Während sie im High-Level Dateizugriff mit einem FILE - Zeiger (FILE *) auf die Datei zugreifen bzw. ansprechen geschieht dies im Low-Level mit einem sogenannten Handle. Ein oder dieser Handle ist kein Zeiger wie im High-Level (FILE *) sondern ein normaler int - Wert der beim Öffnen einer Datei zurückgegeben wird.

Auf Low-Level sind die höheren Dateifunktionen aufgebaut. Low-Level bietet die Grundlage dieser höheren Funktionen in der Standart-Library. Low-Level arbeitet im Gegensatz zum High-Level ungepuffert.

Wenn sie zu, Beispiel die Bibliothekfunktionen wie printf oder scanf zum Aus.-bzw Eingeben benutzen, verwenden sie eigentlich die Systemfunktionen write und read Dies sind Funktionen (Systemfunktionen) im Low-Level-Bereich. Also egal ob sie nun fgets,fputs,gets,puts,putc,getc.....usw. verwenden, all diese Funktionen bauen auf diese Systemfunktionen auf. Nun können wir mit den Funktionen des Low-Level-Datei-I/O beginnen.

Öffnet man eine Datei mit open so wird der Datei ein sogenannter Handle oder auch Filedeskriptor genannt zugeordnet. Über diesen Handle oder Filedeskriptor geben sie an ob nun gelesen oder geschrieben werden kann. Mit der Funktion open können sie nun eine Datei öffnen oder eine Datei anlegen. Hier der Syntax mit Headerdateien die sie mit einbinden müssen für LINUX/UNIX...

#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

int open(const char *pfad, int modus);

...und hier der Syntax und die Headerdateien für DOS/Win - Systeme...

#include <fcntl.h>
#include <io.h>
#include <sys\stat.h>

int open(const char *pfad, int modus);

Die Variable pfad dürfte klar sein. Beim Modus gibt es mehrere Möglichkeiten und diese sind auch teilweise Systemabhängig. Aber einer von diesen 3 Modis muß angegeben werden.....

Modus Bedeutung
O_RDONLY nur zum lesen öffnen (O_RDONLY=0)
O_WRONLY nur zum schreiben öffnen (O_WRONLY=1)
O_RDWR zum lesen und schreiben öffnen (O_RDWR=3)


Dies sieht dann etwa so aus bei Linux/Unix....

int handle;
if((handle = open("/home/programmname", O_RDONLY)) != -1)

...oder bei MS-DOS....

int handle;
if((handle = open("c:\\config.sys", O_RDONLY)) != -1)

In diesem Beispiel würden wir eine Datei nur zum Lesen öffnen. Zu einer dieser 3 Modi oben können sie mit dem Bitweisen ODER - Zeichen ('|') weitere Aktionen verknüpfen oder auch alleine Verwenden. Dies sieht z.B. so aus....

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

Hiermit wird z.B. 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 die sie also mit dem Bitweisen ODER - Zeichen verknüpfen können stehen Ihnen auf LINUX/UNIX und DOS/Win zur Verfügung...

Modus  Bedeutung
O_CREAT Falls Datei nicht existiert wird sie neu angelegt. Falls die Datei existiert wird ist O_CREAT ohne Wirkung.
O_APPEND Datei zu Schreiben am Ende "Anhängen".
O_EXCL O_EXCL kombiniert mit O_CREAT bedeutet das die Datei nicht geöffnet werden kann wenn sie bereits existiert und open den Wert -1 zurückliefert. (-1 == Fehler)
O_TRUNC Eine Datei die zum Schreiben geöffnet wird wird geleert. Das Nachfolgende Schreiben bewirkt erneutes Beschreiben der Datei von Anfang an. Die Attribute der Datei bleiben erhalten.


z.B. würden sie mit folgendem erreichen....

if((handle = open("/home/Name", O_WRONLY | O_TRUNC)) != -1)

...das die Datei Name zum Schreiben geöffnet wird und der Inhalt dieser Datei wird gelöscht und kann neu beschrieben werden. Weiter Modi die nur für UNIX/LINUX gelten sind...

Modus Bedeutung
O_NOCTTY Falls der Pfadname der Name eines Terminal ist, so sollte dies nicht der Kontrollterminal des Prozesses werden.
O_NONBLOCK Falls der Pfadname der Name einer FIFO oder Gerätedatei ist, wird diese beim Öffnen und bei nachfolgenden I/O- Operationen nicht blockiert.
O_SYNC Nach dem Schreiben mit write warten, daß der Schreibvorgang vollständig abgeschlossen ist.


Und nur für DOS gibt es noch folgende Modi...

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


Diese Modi oben können alleine stehen oder eben mit dem Bitweisen ODER - Operator verknüpft werden. Nun folgen noch einige Modi mit denen sie die Zugriffsrechte auf eine Datei erteilen. Zuerst die Modi für DOS....

Modus Bedeutung
S_IWRITE Schreiben erlaubt
S_IREAD Lesen erlaubt
S_IREAD | SIWRITE Lesen und Schreiben erlaubt.


Mit folgender Zeile erzeugen sie eine Datei die nur gelesen werden darf aber nicht beschrieben....

if((handle=open("new.xxx", O_CREAT | S_IREAD)) == -1)

...Wenn sie Lesen und Schreiben erlauben wollen sieht dies wie folgt aus...

if((handle=open("new.xxx", O_CREAT | S_IREAD | S_IWRITE)) == -1)

Diese 3 Zugriffsrechte unter DOS stehen in der Headerdatei <sys\stat.h>.

Für UNIX/LINUX kann man dann folgende Zugriffsrechte erteilen. Bei UNIX/LINUX stehen die Zugriffsrechte in der Headerdatei <sys/stat.h> (Achtung gegenüber DOS '\' -> LINUX '/'). Hier nun die Modi für Linux/Unix....

Modus 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ührrecht 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)


Natürlich kein Kapitel ohne Praxis. Wir wollen eine Datei zum Lesen und Schreiben öffnen (O_RDWR), falls diese nicht existiert wird sie erzeugt (O_CREAT). Falls sie aber existiert wird der Inhalt der Datei gelöscht und neu beschrieben (O_TRUNC). Dies Programm ist auf UNIX/LINUX und MS-DOS/Win lauffähig. Hier der Quellcode dazu.....

/*Download:open1.c*/
#include <stdio.h> #include <stdlib.h> #inlcude <fcntl.h> #ifdef __unix__ #include <unistd.h> #elif __MSDOS__ #include <io.h> #endif int main() { int handle; if((handle=open("adressen.txt", O_RDWR|O_CREAT|O_TRUNC)) == -1) { printf("Fehler\n"); exit (0); } close(handle); return 0; }

Falls sie jetzt noch Zugriffsrechte auf diese Datei vergeben wollen müssen sie noch unter UNIX/LINUX die Headerdatei <sys/stat.h> und unter MS-DOS <sys\stat.h> einbinden. Sie wollen z.B. das unter Linux der user die Datei adressen.txt nur lesen darf, so brauchen sie nur bei dem Modus eine weitere ODER - Verknüpfung mit '|' eingeben und noch S_IRUSR hinzufügen....

open("adressen.txt", O_RDWR | O_CREAT | O_TRUNC|S_IRUSR)) == -1)

Weitere Schreib und Leserechte entnehmen für Linux oder MS-Dos nehmen sie oben aus den Tabellen. Ein weiteres Beispiel von open ist z.B. das Aufrufen von Programmen in der Kommando-Zeile.....

/*Download: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__ #include <io.h> #include <sys\stat.h> #endif main(int argc,char **argv) { int handle; if((handle=open(*++argv,O_RDONLY)) == -1) perror(*argv); else close(handle); return 0; }

Mit diesem Programm wird ein Programm geöffnet dessen Namen sie als 2. Argument in der Kommando-Zeile übergeben. Falls das Programm nicht existiert(== -1) bekommen sie eine Fehlermeldung von perror wie....

Programmname:No such File in Directory

...zurück. Falls kein Fehler erscheint wird der Handle oder Filedeskriptor gleich wieder geschlossen. Falls sie aber die Datei die sie eben aufrufen wollten erzeugen wollen, dann funktioniert das so...

/*Download: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__ #include <io.h> #include <sys\stat.h> #endif int main(int argc,char **argv) { int handle; if((handle=open(*++argv,O_RDONLY)) == -1) if((handle=open(*argv,O_RDWR|O_CREAT,0644)) == -1) printf("Konnte %s nicht oeffnen bzw. erzeugen\n"); close(handle); return 0; }

Somit versuchen sie zuerst die Datei zu öffnen. Falls diese aber nicht existiert wird diese gleich erzeugt zum Lesen und Schreiben. Gelingt dies auch nicht wird sie mit der Permission 0644 angelegt.

In diesem 1.Kapitel des Low-Level-Datei-I/O können sie schon erkennen warum man eher auf High-Level-Datei-I/O zurückgreift. Denn wenn man auf mehreren Systemen Programmiert kann man da schnell durcheinander kommen. Was bei den einem System Funktioniert geht bei dem anderen nicht. Andererseits ist es auch nicht schlecht beim erzeugen einer Datei die Zugriffsrechte von Anfang an festzulegen. Daraus ergibt sich das Low-Level-Datei-I/O vorwiegend zur Systemprogrammierung eignet. Für Linux/Unix-Programmierer stellt diese Art vom öffnen einer Datei eine sehr wichtige Schnittstelle dar. Aber dazu werden wir noch kommen.

Datei schließen - close :

close dient dazu eine Datei mit dem Handle handle zu schließen die sie zuvor mit open oder create geöffnet haben. Denn auch hier können sie nur eine bestimmte Anzahl von Dateien gleichzeitig offen haben. Die Anzahl für max. Dateien steht in der Konstante OPEN_MAX. Hier der Syntax zu close...



int close(int handle);

Der Rückgabewert der Funktion ist bei Fehler -1 ansonsten 0. Hierzu noch ein kurzes Programm....

/*Download:close1.c*/
#include <stdio.h> #include <stdlib.h> #include <fcntl.h> #ifdef __unix__ #include <unistd.h> #elif __MSDOS__ #include <io.h> #endif int main() { int handle; if((handle=open("adressen.txt", O_RDONLY | O_CREAT)) == -1) { printf("Fehler\n"); exit (0); } if((close(handle)) == -1) printf("Fehler beim Schließen der Datei\n"); else printf("Datei wurde ordentlich geschlossen\n"); return 0; }

Wir öffnen mit open eine Datei zum Lesen. Falls sie nicht existiert wird diese erzeugt. Anschließend schließen wir die Datei wieder und überprüfen ob der Schließvorgang Ordnungsmäßig beendet wird. Dieser Schließvorgang dient natürlich nur zur Demonstration. Wenn sie eine Handle schließen werden sie ein einfaches...

close(handle);

...schreiben. Bei Programmende wird wie schon beim High-Level-Datei-I/O die geöffnete Datei automatisch geschlossen.

Verwaltung der geöffneten Dateien (Linux)

Folgende 3 Tabellen verwendet der Kern um geöffnete Dateien zu verwalten...

  • 1. Prozesstabelleneintrag
    Logisch! Jeder Prozess erhält einen einen Eintrag in der Prozesstabelle. In dieser Prozesstabelle befinden sich die Filedeskriptor Flags und ein Zeiger auf auf die Dateitablle. Wo wir gleich bei der 2.Tabelle wären.

  • 2.Dateitabelle
    In der Dateitabelle befindet sich der Zustand der Filedeskriptor Flags, ob z.B. gelesen oder geschrieben wird. Außerdem befindet sich in der Dateitabelle noch die aktuelle Position des Schreib/Lesezeigers und ein Zeiger auf die v-node-Tabelle.

  • 3.v-node-Tabelle
    In der v-node-Tabelle befindet sich der Dateityp, die i-node-Information wie z.B. Eigentümer, Grösse, Zugriffsrechte, i-node-Nummer, Zugriffszeiten... Die Dateigröße finden sie ebenso in der v-node-Tabelle.


Wir werden in den späteren Kapiteln noch Tiefer in das Linux-Filesystem eingehen und sehen wie man an all die Informationen herankommt.

ein Kapitel zurück          nach oben           ein Kapitel weiter


© 2001,2002 Jürgen Wolf