setvbuf()
ist in der stdio
definiert, die in C über stdio.h
, bzw in C++ über cstdio
eingebunden wird.
setvbuf()
gibt den IO-Buffer an, der für den FILE
-Stream verwendet werden soll. Wird NULL übergeben, so wird der Stream nicht gepuffert.
Gepufferte Streams werden nicht sofort auf die Festplatte geschrieben, sondern Lese- und Schreibvorgänge werden zunächst im Buffer gesammelt. Da Dateisysteme Daten in Blöcken ablegen, werden pro Schreibzugriff in der Regel 512 Bytes geschrieben. Würde ein Byte geändert, so muss der vorhandene Block gelesen, verändert und auf das Dateisystem zurückgeschrieben werden. Schreibt man nun Buchstabe für Buchstabe, bedeutet das extrem viel Aufwand, so dass zunächst in einen Puffer geschrieben wird. Wenn der Puffer voll ist, werden die gesammelten Daten an einem Stück übertragen. Wird die Datei mit fclose()
geschlossen, so werden alle noch nicht geschriebenen Daten zunächst auf die Festplatte kopiert. Dies lässt sich auch künstlich durch die fflush()
-Anweisung auslösen, ohne die Datei zu schließen.
Dateien werden automatisch einem Puffer ausgestattet. stdin
, stdout
und stderr
sind ohne Puffer ausgelegt, um Ausgaben sofort an die Konsole liefern zu können.
#include <stdio.h> void setvbuf( FILE * stream, char * buffer, int mode, size_t size );
stream: der zu konfigurierende Stream
buffer: Zeiger auf den Speicherbereich, der als Puffer dienen soll oder NULL
mode: beschreibt, wie der Stream gepuffert werden soll
size: Größe des Puffers
Folgende Modes stehen zur Verfügung:
mode | Beschreibung |
---|---|
_IONBF | No Buffer - keinen Puffer verwenden |
_IOLBF | Line Buffered - Zeilenweise zwischenspeichern |
_IOFBF | Fully Buffered - Block Puffer verwenden |
Wird als buffer
NULL übergeben, so wird bei _IONBF
nicht gepuffert, bei _IOLBF
und _IOFBF
wird automatisch ein Puffer der Größe BUFSIZE
angelegt.
buffer
muss mindestens so groß sein, wie in size
angegeben.
setvbuf()
sollte direkt nachdem die Datei geöffnet wurde und bevor irgendeine Ein- oder Ausgabe über den Stream gelaufen ist.
Sobald Streams gepuffert werden, werden Schreibzugriffe nicht mehr sofort auf den Datenträger geschrieben, sondern zunächst im Puffer gesammelt und anschließend in einem Zug auf den Datenträger geschrieben. Wird die Datei nicht ordnungsgemäß geschlossen, zum Beispiel durch einen Programmabsturz, so werden die Daten, die zunächst im Puffer zwischengespeichert wurden nicht mehr auf den Datenträger geschrieben. Das kann bei der Suche nach dem Fehler eine falsche Spur legen, da Ausgaben, die das Programm gemacht hat, in der Datei nicht mehr auftauchen und man so den Absturz an der Stelle vermutet, an der das Programm den letzten Eintrag in die Datei gesendet hat. Gerade für Log-Files empfiehlt es sich daher, mit setvbuf()
den Puffer auf NULL, die Größe auf 0, sowie den Modus auf _IONBF
zu setzen und damit zu deaktivieren.
Da Programme normalerweise nicht abstürzen sollten, hilft der aktivierte Cache bei korrekten Programmen Lese- und Schreibvorgänge mit wenigen Daten deutlich zu beschleunigen.
#include <stdlib.h> #include <stdio.h> int main (void) { FILE *file = fopen("logfile.txt", "w+"); /* Kommentar in der nächsten Zeile entfernen, um zuverlässig Logfiles zu schreiben */ // setvbuf( file, NULL, _IONBF, 0 ); fprintf( file, "vor Absturz" ); /* Absturz provozieren */ *((int *)0) = 4711; /* Dieser Part wird nicht mehr erreicht */ fprintf( file, "nach Absturz" ); fclose(file); return EXIT_SUCCESS; }
Statt den Puffer komplett abzuschalten, kann man auch den Befehl fflush()
verwenden. Ein entsprechend verändertes Beispiel findet sich dort.
Das Beispielprogramm stürzt absichtlich ab! Es zeigt den Unterschied zwischen einer gepufferten Datei im Fall eines Absturzes und der ungepufferten Datei. Ist setvbuf()
auskommentiert, wird eine Datei logfile.txt
angelegt, die aber nicht mehr beschrieben wird, obwohl der Text „vor Absturz“ zuvor geschrieben werden sollte. Die Dateigröße ist 0. Wird setvbuf()
aufgerufen, so wird der Text „vor Absturz“ auf die Festplatte geschrieben, bevor das Programm in seiner Berechnung fehlschlägt und abstürzt.
Die Funktion setbuf()
entspricht dem folgenden Aufruf der Funktion setvbuf()
:
setvbuf( stream, buffer, buffer ? _IOFBF : _IONBF, BUFSIZ );