ein Kapitel zurück                                           ein Kapitel weiter

Mit setbuf ordnen wir einer Datei einen Puffer zu. Erst mal der Syntax...

void setbuf(FILE *datei, char *puffer);

Das heißt die geöffnete Datei datei bekommt durch setbuf einen Pufferbereich der Größe puffer. Nehmen wir mal an sie haben eine Datei (FILE *datei) Namens quelle geöffnet und eine andere Datei (FILE *datei) Namens ziel. Jetzt schreiben sie z.B....

setbuf(quelle,64);
setbuf(ziel,64);

Nun können sie 64 Bytes von der Datei quelle in die Datei ziel auf einmal kopieren. Wenn sie aber jetzt das gleiche Beispiel so schreiben würden...

setbuf(quelle,NULL);
setbuf(ziel,NULL);

..haben sie keinen Puffer und müsste die Datei ungepuffert von quelle zu ziel kopieren. Das würde bedeuten Zeichen für Zeichen. Und das würde natürlich viel länger dauern da ja jedes Zeichen gelesen und anschließend wieder geschrieben wird. Die Maximale Puffergröße ist in der Headerdatei <stdio.h> mit dem Namen BUFSIZ definiert. Also könnten sie mit setbuf auch die Standartgröße des Puffer übergeben, wieder unser Beispiel oben...

setbuf(quelle,BUFSIZ);
setbuf(ziel,BUFSIZ);

Wie viel die Standartgröße (maximale Größe der Pufferung) bei Ihnen sein kann können sie mit folgendem Programm testen...

/*Download:bufsiz.c*/
#include <stdio.h> int main() { printf("Die Standart Größe ihres Puffers beträgt %d\n",BUFSIZ); return 0; }

Der eine wird 256 der andere 512 und vielleicht auch 1024 als BUFSIZ definiert haben. Das ist abhängig vom System und Compiler. Nun will ich das ganze wieder in ein Beispiel packen. Ich stelle wieder Gepufferte und Ungepufferte Dateien im Vergleich gegenüber. Zuerst kopieren wir gepuffert und anschließend ungepuffert. Zur Demonstration benutze ich außerdem getc und putc zum lesen und schreiben, da diese beiden Funktionen ja normalerweise Zeichen weise Lesen und Schreiben aber auch vom Puffer abhängig sind.

/*Download:setbuf.c*/
#include <stdio.h> #include <stdlib.h> #include <time.h> #define DATEIGROESSE 1000000L #define DATEI1 "test.1" #define DATEI2 "test.2" void copy1(char *quelle, char *ziel) { FILE *q,*z; int c; time_t t1 = time(NULL); printf("Kopiere ohne irgendeine Puffereinstellung mit setbuf\n"); if((q=fopen(quelle,"rb")) != NULL) { if((z=fopen(ziel,"wb")) == NULL) { fprintf(stderr,"Fehler beim oeffnen von %s\n",ziel); exit (0); } } else { fprintf(stderr,"Fehler beim oeffnen von %s\n",quelle); exit (1); } while((c=getc(q)) != EOF) putc(c,z); fclose(q); fclose(z); printf("Zeit = %d sec.\n",time(NULL)-t1); } void copy2(char *quelle, char *ziel) { FILE *q,*z; static char puffer1[BUFSIZ]; static char puffer2[BUFSIZ]; int c; time_t t1 = time(NULL); printf("Kopiere gepuffert\n"); if((q=fopen(quelle,"rb")) != NULL) { if((z=fopen(ziel,"wb")) == NULL) { fprintf(stderr,"Fehler beim oeffnen von %s\n",ziel); exit (0); } } else { fprintf(stderr,"Fehler beim oeffnen von %s\n",quelle); exit (1); } setbuf(q,puffer1); setbuf(z,puffer2); while((c=getc(q)) != EOF) putc(c,z); fclose(q); fclose(z); printf("Zeit = %d sec.\n",time(NULL)-t1); } void copy3(char *quelle, char *ziel) { FILE *q,*z; int c; time_t t1 = time(NULL); printf("Kopiere ungepuffert\n"); if((q=fopen(quelle,"rb")) != NULL) { if((z=fopen(ziel,"wb")) == NULL) { fprintf(stderr,"Fehler beim oeffnen von %s\n",ziel); exit (0); } } else { fprintf(stderr,"Fehler beim oeffnen von %s\n",quelle); exit (1); } setbuf(q,NULL); setbuf(z,NULL); while((c=getc(q)) != EOF) putc(c,z); fclose(q); fclose(z); printf("Zeit = %d sec.\n",time(NULL)-t1); } void erzeuge_datei() { FILE *create; if((create=fopen(DATEI1,"wb")) == NULL) { fprintf(stderr,"Konnte keine Datei erzeugen\n"); exit (2); } fseek(create,DATEIGROESSE-1,SEEK_SET); putc('x',create); fclose(create); } int main() { printf("Datei %s wird erzeugt\n",DATEI1); erzeuge_datei(); copy1(DATEI1,DATEI2); copy2(DATEI1,DATEI2); copy3(DATEI1,DATEI2); remove(DATEI1); remove(DATEI2); return 0; }

Diese Programm setzt mindestens 2MB Festplattenplatz voraus. Als erstes erzeugen wir eine Datei von der Größe von 1 Megabyte mit der Funktion erzeuge_datei(). Anschließend kopieren wir die erzeugte Datei test.1 in die Datei test.2 ohne der Funktion setbuf(Funktion copy1). Diese Zeit wird bei manchen 1 Sekunde oder bei anderen sogar 0 Sekunden anzeigen. Also diese Version eine Datei zu kopieren geht ziemlich schnell voran. Als nächstes nutzen wir die Funktion copy2(....) bei der zum ersten mal setbuf einsetzen. Wir benutzen hier die Größe BUFSIZ die in der Headerdatei <stdio.h> definiert ist. Die Zeit ist wieder die selbe wie eben schon zuvor ohne setbuf. Also 0 oder 1 Sekunde (Vorrausgesetzt sie benutzen keinen Pentium 33MHZ). Also könnten wir uns eigentlich setbuf mit der Größe von BUFSIZ sparen, da dies die Standarteinstellung für getc und putc zu sein scheint. Als nächstes wird die Funktion copy3(...) ausgeführt bei der wir unseren Puffer auf NULL setzen. Folge dessen kopieren wir jetzt unsere Datei test.1 jetzt ungepuffert. Und das dauert natürlich da nach jedem Lesenzugriff pro Byte gleich wieder ein Schreibzugriff erfolgt. Bei mir (500MHZ Celron) auf dem Laptop dauerte dies geschlagene 25 Sekunden. Am Schluss des Programms werden die beiden Dateien wieder gelöscht mittels remove damit nicht unnötig Datenmüll auf Ihrer Platte bleibt. Das Programm ist eigentlich unnötig lang. Denn hier werden 3 mal Daten geöffnet kopiert und wieder geschlossen. Versuchen sie mal zur Übung das Programm um mindestens die Hälfte zu kürzen. Meine Lösung könnte ihr euch hier anschauen.

Nun wird zur Puffereinstellung heute kaum noch auf setbuf zurückgegriffen aber da setbuf zum ANSII - C gehört habe ich es ebenfalls durchgenommen. Zur Puffereinstellung können sie auch setvbuf benutzen. Hierzu der Syntax....

int setvbuf(FILE *datei,char *puffer, int modus,size_t puffergroesse);

Mit setvbuf übergeben sie ebenfalls wie mit setbuf einer geöffneten Datei einen Puffer. Die Funktion liefert 0 bei Erfolg und ungleich 0 bei Fehler zurück. Die ersten beiden Parameter (FILE *datei,char *puffer) haben die selbe Bedeutung wie bei setbuf. Bei dem modus stehen Ihnen drei verschiedene zur Verfügung....

Puffertyp (Modus) Bedeutung
_IOFBF Datei wird Vollgepuffert
_IOLBF Datei wird zeilenweise Gepuffert
_IONBF Ein-/Ausgabe wird gar nicht gepuffert


Falls sie bei puffer NULL eingeben alloziert die Funktion einen eigenen Speicher der Größe von puffergrösse. Das ganze hört sich komplexer an als es ist. Nehmen wir z.B. setbuf ohne Pufferung...

setbuf(quelle,NULL);

Hiermit haben wir für die Datei auf den der FILE - Zeiger quelle zeigt keine Puffer eingestellt (ungepuffert). Wie schon oben bei setbuf gelernt. Dies sieht dann mit setvbuf so aus...

setvbuf(quelle, NULL, _IONBF, BUFSIZ);

Hiermit haben wir das selbe erreicht wie mit setbuf. Wir haben für die Datei auf die quelle zeigt den Puffer ausgeschalten. Wenn sie jetzt z.B. 50KB auf einmal Puffern wollen also von Datei quelle nach Datei ziel kopieren so ergeben sich bei setvbuf folgende Parameter...

setvbuf(quelle, NULL, _IOFBF, 50000L);
setvbuf(ziel, NULL, _IOFBF, 50000L);

Oder nehmen wir mal an sie wollen Zeilenweise Puffern. Dies machen sie wenn wieder von quelle nach ziel kopieren wollen so...

setvbuf(quelle, NULL, _IOLBF, 80);
setvbuf(ziel, NULL, _IOLBF, 80);

Hiermit werden von quelle nach Ziel mindestens 80 Zeichen kopiert oder bis zum nächsten '\n'. Wenn sie wollen können sie diese Art von Pufferungen in dem Programm oben durch setbuf ersetzen und einfach setvbuf einfügen die ich Ihnen hier gezeigt habe.

ein Kapitel zurück          nach oben           ein Kapitel weiter


© 2001,2002 Jürgen Wolf