Ein einfaches mmap() Readonly-Beispiel

English Deutsch

Problem:

Du möchtest mmap() aus dem POSIX-Header sys/stat.h verwenden, um eine Datei für Lesezugriff (nicht Schreibzugriff) zu mappen. Du findest kein einfaches nacktes Beispiel im Internet.

Lösung

Wenn du nur an einem High-Level-Wrapper interessiert bist, schau dir dieses boost::iostreams mmap-Beispiel und die boost::iostreams mmap-Referenz an. Beachte jedoch, dass boost::iostreams nicht die gesamte Funktionalität von mmap() bietet und boost::iostreams eine ziemlich große Abhängigkeit ist (man muss die Bibliothek linken!). Es könnte jedoch die beste Option für bessere Portabilität auf Nicht-Unix-Systeme sein.

Hier ist eine minimale mmap()-basierte cat-Implementierung. Sie ist nicht effizient, demonstriert aber die wichtigsten Konzepte. Sie verwendet die stat()-basierte getFilesize()-Funktion aus diesem vorherigen Beitrag.

mmap_cat_example.cpp
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <assert.h>

size_t getFilesize(const char* filename) {
    struct stat st;
    stat(filename, &st);
    return st.st_size;
}

int main(int argc, char** argv) {
    size_t filesize = getFilesize(argv[1]);
    //Datei öffnen
    int fd = open(argv[1], O_RDONLY, 0);
    assert(fd != -1);
    //mmap ausführen
    void* mmappedData = mmap(NULL, filesize, PROT_READ, MAP_PRIVATE | MAP_POPULATE, fd, 0);
    assert(mmappedData != MAP_FAILED);
    //Die gemappten Daten auf stdout schreiben (= FD #1)
    write(1, mmappedData, filesize);
    //Aufräumen
    int rc = munmap(mmappedData, filesize);
    assert(rc == 0);
    close(fd);
}

Kompilieren mit

build_mmap_example.sh
g++ -o mmap-example mmap-example.cpp

Ausführen wie folgt:

run_mmap_example.sh
echo "hello mmap world" > test.txt
./mmap-example test.txt

Schritt-für-Schritt-Diskussion

Schritt 1: Dateigröße ermitteln. Diese musst du vor dem Aufruf von mmap kennen, aber du kannst auch nur eine Teilmenge mappen.

Schritt 2: Datei öffnen. Beachte, dass du die Funktion fopen() nicht direkt verwenden kannst (du könntest fileno() auf das FILE-Objekt anwenden), da du den Dateideskriptor brauchst! In diesem Fall verwenden wir O_RDONLY, weil wir mmap() nur-lesen verwenden wollen.

Schritt 3: mmap() mit diesen Parametern aufrufen:

Eine detaillierte mmap()-Referenz findest du auf der Opengroup-Seite zu mmap

Fehlerprüfung

Die obige Implementierung prüft nicht ordnungsgemäß auf Fehler, da es nur ein minimales Beispiel ist.

In jedem Fall solltest du zumindest prüfen, ob der von mmap() zurückgegebene Wert == MAP_FAILED ist. Siehe die Opengroup-Seite zu mmap für Details.

Update 2013/09/26: Dateideskriptor im Cleanup-Abschnitt schließen Update 2016/01/07: != MAP_FAILED statt NULL asserten (Danke an Erik Sjölund)


Check out similar posts by category: C/C++