Memory Mapped Files

Damit wird eine Datei ein Zusätzlicher Teil des Speichers, denn ein Prozess besitzt. Dieser Speicher muss nicht eplizit reserviert oder freigegeben werden, die passenden Speicheraddressen sind direkt auf die Festplatte gelinkt.

Welche Befehle existieren?

Datei öffnen:

HANDLE hFile = CreateFile(FileName, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, 0);

MemoryMap auf die Datei erstellen:

hMap = CreateFileMapping(hFile, 0, PAGE_READONLY, 0, 0, 0);

Noch den Speicher auf die Datei umbiegen:

pVoid = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);

Nun zeigt pVoid auf den Speicherbereich, der sich physikalisch auf der Festplatte befindet und gleichzeit im 4GB-Addressbereich der Anwendung. Nach der Bearbeitung muss auch noch aufgeräumt werden:

UnmapViewOfFile(pVoid);
CloseHandle(hMap); 
CloseHandle(hFile);

Und nun noch eine Klasse als Beispiel:

Die MMap.h

#pragma once

#define WIN32_LEAN_AND_MEAN
#include 
#include 

#ifdef MMAP_EXPORTS
#define MMAP_API __declspec(dllexport)
#else
#define MMAP_API __declspec(dllimport)
#endif

namespace READER {
  class MMap {
    private:
      HANDLE hFile;
      HANDLE hMap;
      PVOID pVoid;
    public:
      MMAP_API MMap( const char* pFileName, PBYTE* ppPuffer );
      MMAP_API MMap( const wchar_t* pFileName, PBYTE* ppPuffer );
      MMAP_API ~MMap();
  }
}

Und noch die MMap.cpp:

#include "MMap.h"
namespace READER {
  MMap::MMap( const char* pFileName, PBYTE* ppPuffer ) : hFile(0), hMap(0), pVoid(0) {
    hFile=CreateFileA( pFileName, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, 0 );
    if( hFile==INVALID_HANDLE_VALUE ) {
      hFile=0;
      throw std::string("Fehler: Datei existiert nicht oder lässt sich nicht öffnen.");
    }
    DWORD FileSize;
    FileSize=GetFileSize( hFile, 0 );
    if( !FileSize ) {
      CloseHandle(hFile);
      hFile=0;
      throw std::string("Fehler: Datei ist leer.");
    }

    hMap=CreateFileMappingA( hFile, 0, PAGE_READONLY, 0, 0, 0 );
    if( hMap==INVALID_HANDLE_VALUE ) {
      CloseHandle(hFile);
      hFile=0;
      hMap=0;
      throw std::string("Fehler: Mapping nicht möglich.");
    }
    pVoid = MapViewOfFile( hMap, FILE_MAP_READ, 0, 0, 0 );
    if( !pVoid ) {
      CloseHandle( hMap );
      CloseHandle( hFile );
      hMap=0;
      hFile=0;
      throw std::string("Fehler: Mapping nicht möglich.");
    }
    *ppPuffer = (PBYTE)pVoid;
  }

  MMap::MMap(const wchar_t* pFileName, PBYTE* ppPuffer) : hFile(0), hMap(0), pVoid(0) {
    hFile = CreateFileW( pFileName, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, 0 );
    if( hFile==INVALID_HANDLE_VALUE ) {
      hFile=0;
      throw std::string("Fehler: Datei existiert nicht oder lässt sich nicht öffnen.");
    }
    DWORD FileSize;
    FileSize=GetFileSize(hFile, 0);
    if( !FileSize ) {
      CloseHandle(hFile);
      hFile=0;
      throw std::string("Fehler: Datei ist leer.");
    }
    hMap=CreateFileMappingW(hFile, 0, PAGE_READONLY, 0, 0, 0);
    if( hMap==INVALID_HANDLE_VALUE ) {
      CloseHandle(hFile);
      hFile=0;
      hMap=0;
      throw std::string("Fehler: Mapping nicht möglich.");
    }
    pVoid=MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
    if( !pVoid ) {
      CloseHandle(hMap);
      CloseHandle(hFile);
      hMap=0;
      hFile=0;
      throw std::string("Fehler: Mapping nicht möglich.");
    }
    *ppPuffer=(PBYTE)pVoid;
  }

  MMap::~MMap() {
    if(pVoid) {
      UnmapViewOfFile(pVoid);
    }
    if(hMap) {
      CloseHandle(hMap);
      hMap=0;
    }
    if(hFile) {
      CloseHandle(hFile);
      hFile=0;
    }
  }
}

Die vorher definierte Klasse ist eher für eine Funktions-Dll gedacht. Und so wird sie verwendet:

PBYTE pPuffer;
READER::MMap MyMap( "Dateiname und Pfad", %pPuffer );
std::cout << pPuffer;

VORSICHT: Die Klasse ist aktuell nur zum lesen ausgelegt.