Speicherbasierte Streams
Nicht alle Ein-/Ausgabeoperationen erfordern physische Dateien. Ein speicherbasierter Stream stellt die gewohnte FILE *-Schnittstelle bereit, arbeitet aber auf einem Speicherpuffer. Das erlaubt Formatierung, Parsing und Tests ohne Dateizugriffe.
Einen Stream auf einen Speicherbereich öffnen (fmemopen())
Die Funktion fmemopen() (POSIX-Erweiterung, seit POSIX.1-2008) öffnet einen Stream auf einem vorgegebenen Speicherbereich.
FILE *fmemopen(void *buf, size_t size, const char *mode);
Man übergibt einen void *-Zeiger auf den Puffer, der als ›Dateiinhalt‹ dient, sowie die Länge. Der Öffnungsmodus entspricht fopen() ("r" ab 0 lesen, "w" löschen und schreiben, "a" ans Ende anhängen, usw.). Der Stream arbeitet strikt innerhalb der angegebenen Größe und verhindert Überläufe.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char buffer[100];
// Explizite Initialisierung mit strncpy für Sicherheit
strncpy(buffer, "Erste Zeile\nZweite Zeile", sizeof(buffer) - 1);
// Null-Terminierung gewährleisten
buffer[sizeof(buffer) - 1] = '\0';
// strlen für exakte Länge
FILE *stream = fmemopen(buffer, strlen(buffer), "r");
if (stream == nullptr) {
perror("Fehler beim Öffnen des Speicher-Streams");
return EXIT_FAILURE;
}
char line[50];
while (fgets(line, sizeof(line), stream) != nullptr) {
printf("Gelesen: %s", line);
// 📣 Gelesen: Erste Zeile\nGelesen: Zweite Zeile
}
if (fclose(stream) == EOF) {
perror("fclose");
return EXIT_FAILURE;
}
}
Beim Öffnen erzeugt die Implementierung eine interne Positionsverwaltung und verknüpft sie mit dem Puffer. Leseoperationen liefern Daten ab der aktuellen Position, Schreiboperationen überschreiben oder erweitern den Inhalt im Rahmen der Puffergröße.
Hauptanwendungsfall ist das Testen von Funktionen, die auf FILE * angewiesen sind. Statt Dateien auf dem Dateisystem zu erzeugen, lädt man Testdaten in einen Puffer und verwendet fmemopen(). Das ist schneller, reproduzierbar und dateisystemunabhängig.
In einen dynamischen Speicherstream schreiben (open_memstream())
open_memstream() ist eine POSIX-Erweiterung für ausschließlich schreibbare, dynamische Speicherstreams. Im Unterschied zu fmemopen() verwaltet diese Funktion den Puffer dynamisch: Beim Schreiben wächst er automatisch. Die Signatur ist:
FILE *open_memstream(char **bufp, size_t *sizep);
bufp zeigt auf einen char *, der nach dem ersten Schreibvorgang den erzeugten Puffer referenziert. sizep liefert nach fclose() die endgültige Länge des Inhalts. Zugriffe auf buffer vor fclose() können unvollständige oder inkonsistente Daten liefern.
Der zurückgegebene Puffer muss mit free() freigegeben werden.
Nach fclose() ist der Puffer vollständig und kann beliebig verwendet oder kopiert werden. Änderungen daran beeinflussen den Stream nicht mehr.
Fassen wir zusammen: open_memstream() erfordert keine vorherige Größenplanung. Der Puffer wächst automatisch und eignet sich für Ausgaben mit unbekanntem Umfang wie JSON-Erzeugung, Logzeilen oder dynamische Textausgaben. Der Stream erlaubt aber nur Schreibzugriff; zum Lesen dient ein separater Stream, etwa über fmemopen().