![ein Kapitel weiter](../weiter.gif)
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 weiter](../weiter.gif)
© 2001,2002 Jürgen Wolf
|