setvbuf()

setvbuf() ist in der stdio definiert, die in C über stdio.h, bzw in C++ über cstdio eingebunden wird.

Funktion

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.

Signatur

#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.

Fehlerquellen

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.

Beispiel

#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.

Hinweis

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 );

siehe auch