ein Kapitel zurück                                           ein Kapitel weiter

Die Funktion write dient zum unformatierten Schreiben in die Datei mit dem Handle, der mittels 'open' oder 'create' an den Handle übergeben wurde. Hier der Syntax...

#include <unistd.h>    //für UNIX/LINUX
#include <io.h>     //für MS-DOS

int write(int handle, const void *puffer, size_t bytezahl);

Mit write schreiben wir also unformatiert in die Datei mit dem Handle handle. Um den geeigneten Handle zu erhalten muss die Datei zuvor mittels open oder create geöffnet worden sein. Dann schreibt write von der Datei mit dem Handle handle bytezahl Bytes in die Speicheradresse des Puffers puffer. Dieser Puffer ist wieder ein typenloser void - Zeiger und kann sich somit jeden beliebigen Variablentypes annehmen. Bei Fehler liefert diese Funktion den Wert -1 zurück ansonsten die Anzahl der geschriebenen Bytes. Hierzu ein einfaches Beispiel von write....

/*Download:write1.c*/
#include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <string.h> #ifdef __unix__ #include <unistd.h> #elif __MSDOS__ #include <io.h> #endif int main() { int handle; char puffer[100]; strcpy(puffer,"Dieser Text steht in \"test.txt\"\n"); if((handle=open("test.txt",O_RDWR|O_CREAT|O_TRUNC)) == -1) { printf("Fehler beim öffnen der Datei \"test.txt\"\n"); exit (0); } if((write(handle, &puffer, sizeof(puffer))) == -1) { printf("Fehler bei write........\n"); exit (1); } printf("Datei wurde erfolgreich in \"test.txt\" geschrieben\n"); return 0; }

Wir kopieren mit strcpy einen Text in unseren Puffer, öffnen eine Datei bzw. erzeugen eine mit 'open'. Damit haben wir einen Handle für unsere Datei. Als nächstes schreiben wir mit 'write' von der Adresse des Puffers (&puffer) die Größe von (sizeof(puffer)) Bytes in die Datei mit unserem Handle handle. Nun haben sie in dem Verzeichnis in dem sie dieses Programm ausführen eine Datei Namens "test.txt" mit dem Inhalt den wir mit strcpy in den Puffer kopiert haben. Nun eignet sich write genauso wie fwrite dazu Datenstrukturen in eine Datei zu schreiben. Ich will ihnen das nicht vorenthalten...

/*Download:write2.c*/
#include <stdio.h> #include <stdlib.h> #include <string.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 #define MAXADRESSEN 10 struct kunde { char name[20]; char vorname[20]; int kundenummer; char ort[30]; char strasse[30]; int hausnummer; int vorwahl; int telefonnr; }; struct kunde k[MAXADRESSEN]; static int counter=0; void neukunde() { int handle; if(counter==MAXADRESSEN) printf("Kein Speicherplatz mehr frei!!!\n"); else { printf("Name...................: "); scanf("%s",k[counter].name); printf("Vorname................: "); scanf("%s",k[counter].vorname); k[counter].kundenummer=counter; printf("Ort....................: "); scanf("%s",k[counter].ort); fflush(stdin); printf("Strasse................: "); scanf("%s",k[counter].strasse); fflush(stdin); printf("Hausnummer.............: "); scanf("%d",&k[counter].hausnummer); fflush(stdin); printf("Vorwahl................: "); scanf("%d",&k[counter].vorwahl); fflush(stdin); printf("Telefonnummer..........: "); scanf("%d",&k[counter].telefonnr);fflush(stdin); if((handle=creat("kunden.dat",S_IREAD|S_IWRITE)) == -1) printf("Konnte\"kunden.dat\" nicht öffnen\n"); else if((write(handle,&k,sizeof(k))) == -1) printf("Konnte nicht in \"kunden.dat\" schreiben\n"); else counter++; } } int main() { int wahl; do{ printf("\t1: Neuen Kunden eingeben\n\n"); /*printf("\t2: Kunden ausgeben\n\n");*/ printf("\t3: Programmende\n\n"); printf("\tEingabe :> "); scanf("%d",&wahl); switch(wahl) { case 1 : neukunde(); break; /*case 2 : lese(); break;*/ case 3 : printf("bye\n"); break; default: printf("Falsche Eingabe!!!\n"); break; } }while(wahl != 3); return 0; }

Zuerst übergeben wir in der Funktion neukunde() unsere Daten an die Struktur...

struct kunde k[MAXADRESSEN];

...wie wir es schon in den Kaptitel der Strukturen kennen gelernt haben. Anschließend erzeugen wir mit...

if((handle=creat("kunden.dat",S_IREAD|S_IWRITE)) == -1)

...creat eine Datei Namens "kunden.dat" zum lesen und schreiben. Jetzt können wir mittels...

else if((write(handle,&k,sizeof(k))) == -1)

... in unsere Datei mit dem Handle handle(kunden.dat) von der Adresse struct kunde k mit Größe der Struktur (sizeof(k)) schreiben. Anschließend wird der counter auch noch um 1 erhöht. Lassen sie sich nicht verwirren von der if-ifelse-else Anweisungen. Bei Richtigkeit werden diese alle 3 Ausgeführt solange keine der Funktionen -1 (Fehler) zurückliefert. Nun befindet sich bei Erfolg in dem Verzeichnis in dem sie das Programm ausführen eine Datei Namens "kunden.dat". Diese werden sie wenn sie diese mit einem Texteditor öffnen nicht lesen können. Da wie gesagt schreiben wir im Low-Level-Datei-I/O unformatiert in eine Datei.

Anmerkung zu write : Das Schreiben mit write wird über einen Puffercache durchgeführt, bevor wirklich auf die Festplatte, Diskette... geschrieben wird. Dieses delayed write birgt die Gefahr bei einem Systemabsturz, das noch sich im Cache befindliche Daten, nicht physikalisch auf Festplatte, Disk... etc. geschrieben werden. In diesem Fall kann man die Datei zum schreiben im O_SYNC - Modus öffnen. Dieser Modus wartet auf jedem physikalischem Schreibvorgang bis dieser fertig ist und liest dann erst wieder Daten ein. Dieser Modus hat aber auch leider den Nachteil schrecklich langsam zu sein. Zwei Funktionen die es dazu gibt unter Linux sind sync und fsync die wir aber in diesem Kurs nicht durchnehmen wollen. Linux-User lesen bitte entsprechende man-pages falls diese Funktionen benötigt werden.

read

Nun benötigen wir eine weiter Funktion damit wir diese Daten auch wieder lesen können. Dazu dient die Funktion read.

Der Syntax von read fast der gleiche wie bei write....

int read(int handle, const void *puffer, site_t bytezahl);

Mit read lesen sie bytezahl Bytes aus der Datei mit dem Handle handle. Die Daten werden dann in die Adresse von puffer gelegt. Somit steht die Datei des Handle in dem Puffer puffer. Zuvor muss natürlich die Datei mit dem Handle handle mit open oder create geöffnet werden. Auch hier gilt bei Fehler liefert die Funktion -1. Ansonsten wenn alles richtig verlief 0. Hierzu ein Beispiel wie sie eine Datei kopieren....

/*Download:read1.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 #define MAXBYTES 1024 main(int arg, char **argv) { int in,out,count; char buffer[MAXBYTES]; if((in=open(*++argv,O_RDONLY)) == -1) printf("Fehler open %s\n",argv); if((out=open(*++argv,O_WRONLY|O_TRUNC|O_CREAT,0644))== -1) printf("Fehler open %s\n",argv); while(count = read(in,buffer,MAXBYTES)) write(out,buffer,count); close(in); close(out); }

Mit diesem Programm kopieren sie das 2. Argument enthaltene Datei der Kommandozeile in das 3. Argument enthaltene Datei (falls beide Dateien vorhanden sind).

Jetzt wollen wir noch unser 1. Programm oben mit der Funktion read Ergänzen bevor wir unser Datenstruktur damit bestücken....

/*Download:read2.c*/
#include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <string.h> #ifdef __unix__ #include <unistd.h> #elif __MSDOS__ #include <io.h> #endif int main() { int handle; char puffer[100]; char pufferneu[100]; strcpy(puffer,"Dieser Text steht in \"test.txt\"\n"); if((handle=open("test.txt",O_RDWR|O_CREAT|O_TRUNC)) == -1) { printf("Fehler beim öffnen der Datei \"test.txt\"\n"); exit (0); } if((write(handle, &puffer, sizeof(puffer))) == -1) { printf("Fehler bei write........\n"); exit (1); } close(handle); if((handle=open("test.txt",O_RDONLY)) == -1) { printf("Fehler beim 2. Oeffnen von test.txt\n"); exit (2); } if((read(handle, &pufferneu, sizeof(pufferneu))) == -1) { printf("Fehler bei read.........\n"); exit (3); } printf("%s",pufferneu); close(handle); return 0; }

Das Programm kennen sie bereits bis zu write. Nun lesen wir mit read die Größe von sizeof(pufferneu) Bytes mit dem Handle handle den wir mit open geöffnet haben in die Adresse von pufferneu. Anschließend geben wir pufferneu mit printf auf dem Bildschirm aus. Ich schätze mal das Programm bereitet keinem mehr Kopfzerbrechen. Nun wollen wir das selbe mit dem 2. Programm mit write auch machen. Schließlich wollen wir ja die Daten die wir schreiben auch wieder lesen können...

/*Download:rdwr.c*/
#include <stdio.h> #include <stdlib.h> #include <string.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 #define MAXADRESSEN 10 struct kunde { char name[20]; char vorname[20]; int kundenummer; char ort[30]; char strasse[30]; int hausnummer; long vorwahl; long telefonnr; }; struct kunde k[MAXADRESSEN]; static int counter=0; void neukunde() { int handle; if(counter==MAXADRESSEN) printf("Kein Speicherplatz mehr frei!!!\n"); else { printf("Name...................: "); scanf("%s",k[counter].name); printf("Vorname................: "); scanf("%s",k[counter].vorname); k[counter].kundenummer=counter; printf("Ort....................: "); scanf("%s",k[counter].ort); fflush(stdin); printf("Strasse................: "); scanf("%s",k[counter].strasse); fflush(stdin); printf("Hausnummer.............: "); scanf("%d",&k[counter].hausnummer); fflush(stdin); printf("Vorwahl................: "); scanf("%ld",&k[counter].vorwahl); fflush(stdin); printf("Telefonnummer..........: "); scanf("%ld",&k[counter].telefonnr);fflush(stdin); if((handle=creat("kunden.dat",S_IREAD|S_IWRITE)) == -1) printf("Konnte\"kunden.dat\" nicht öffnen\n"); else if((write(handle,&k,sizeof(k))) == -1) printf("Konnte nicht in \"kunden.dat\" schreiben\n"); else counter++; } } void lese() { int handle; int num; printf("Bitte geben sie die Kundennummer ein : "); scanf("%d",&num); if((handle=open("kunden.dat",O_RDONLY)) == -1) { printf("Kann Kundendatei nicht öffnen"); exit (0); } read(handle,&k,sizeof(k)); printf("\n\n"); printf("Name..........%s\n",k[num].name); printf("Vorname.......%s\n",k[num].vorname); printf("Kundennummer..%d\n",k[num].kundenummer); printf("Wohnort.......%s\n",k[num].ort); printf("Strasse.......%s\n",k[num].strasse); printf("Hausnummer....%d\n",k[num].hausnummer); printf("Vorwahl.......%ld\n",k[num].vorwahl); printf("Telefonnum....%ld\n",k[num].telefonnr); } int main() { int wahl; do{ printf("\t1: Neuen Kunden eingeben\n\n"); printf("\t2: Kunden ausgeben\n\n"); printf("\t3: Programmende\n\n"); printf("\tEingabe :> "); scanf("%d",&wahl); switch(wahl) { case 1 : neukunde(); break; case 2 : lese(); break; case 3 : printf("bye\n"); break; default: printf("Falsche Eingabe!!!\n"); break; } }while(wahl != 3); return 0; }

Unser Datenprogramm ist wieder um eine Funktion reifer geworden. Nämlich der Funktion lese(). Bei dieser öffnen wir mit....

if((handle=open("kunden.dat",O_RDONLY)) == -1)

..unser Kundendatei zum lesen. Anschließend lesen wir die Kundendatei mit....

read(handle,&k,sizeof(k));

....aus und übergeben sizeof(k) Bytes auf die unsere Handle handle zeigt an die Adresse von k. Anschließend werden die Kundendaten auf dem Bildschirm ausgegeben. Wie sie schon gemerkt haben werden, besonders komfortabel ist das Programm nicht. Denn immer wenn sie das Programm neu starten werden wenn sie neue Adressen eingeben wollen die ersten wieder überschrieben. Nun bräuchten wir hier auch so etwas wie einen Dateipositionierzeiger. Aber dazu mehr im nächsten Kapitel.

Wir vergleichen zwei Dateien, die sie in der Kommandozeile eingeben. Wir vergleichen diese beiden Programme Byteweise. Zunächst aber nochmals zu den Filedeskriptoren oder wie wir sie nennen Handle. Sie kennen nun folgende Möglichkeiten.....

write(handle, &puffer, sizeof(puffer));

read(handle, &puffer, sizeof(puffer));

Anstatt des Handle handle können wir auch Zahlen verwenden (0,1,2). Jede dieser 3 Zahlen hat folgende Bedeutung....

Zahl Bedeutung
0 Standarteingabe (stdin)
1 Standartausgabe (stdout)
2 Standartfehlerausgabe (stderr)


Dies würden nun bedeuten wenn sie folgendes schreiben...

/*Download:rdwr1.c*/
#include <stdio.h> #ifdef __unix__ #include <unistd.h> #elif __MSDOS__ #include <io.h> #endif int main() { char puffer[100]; read(0, &puffer, sizeof(puffer)); printf("%s",puffer); return 0; }

Mit read(0, &puffer, sizeof(puffer)) lesen wir aus der Standarteingabe (stdin) in die Adresse des Puffers. Also von der Tastatur. Wenn wir nun mit write auf dem Bildschirm schreiben wollen würde dies so aussehen...

/*Download:rdwr2.c*/
#include <stdio.h> #ifdef __unix__ #include <unistd.h> #elif __MSDOS__ #include <io.h> #endif int main() { char puffer[] = "Ich werde im Low-Level-I/O ausgegeben"; write(1, &puffer, sizeof(puffer)); return 0; }

Also nun zu dem Programm das unsere 2 Dateien auf Gleichheit überprüft.....

/*Download:mydiff.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 #define ERROPEN "Konnte %s nicht oeffnen\n" char error[]= "Benutzung: Programmname Datei1 Datei2"; int main(int argc, char *argv[]) { int handle1,handle2,gelesen1,gelesen2; char puffer1[2],puffer2[2]; unsigned long i=1; if(argc != 3) { write(2,&error,sizeof(error)); exit (0); } /*Öffnen der beiden Dateien*/ if((handle1=open(argv[1],O_RDONLY)) != -1) { if((handle2=open(argv[2],O_RDONLY)) == -1) { printf(ERROPEN,argv[2]); exit(1); } } else { printf(ERROPEN,argv[1]); exit (0); } /*Wir prüfen die Bytes nacheinander*/ while(1) /*Endlosschleife*/ { if((gelesen1=read(handle1, &puffer1, 1)) != -1) if((gelesen2=read(handle2, &puffer2, 1)) != -1) if(gelesen1==0 && gelesen2==0) { printf("%s und %s sind identisch\n",argv[1],argv[2]); return 0; } else if(gelesen1==0) { printf("%s ist kleiner als %s\n",argv[1],argv[2]); exit (1); } else if(gelesen2==0) { printf("%s ist grösser als %s\n",argv[1],argv[2]); exit (1); } else { if(puffer1[0] != puffer2[0]) { printf("%ld. Bytenr.:(%s:x0%02x) <> (%s:x0%02x)\n", i,argv[1],puffer1[0],argv[2],puffer2[0]); exit (1); } else i++; } } /*Ende while(1)*/ return 0; }

Das Programm bricht ab sobald eine oder beide Lesefunktionen 0 zurückliefert. Oder beim ersten Zeichen das nicht mehr übereinstimmt.

ein Kapitel zurück          nach oben           ein Kapitel weiter


© 2001,2002 Jürgen Wolf