Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Проецирование файлов на память


Автор: chipset 31.1.2005, 05:36
 Практические примеры - на WinAPI, и на MFC

Теория:
Файл, спроецированный на память - это механизм Win32 API, позволяющий любой открытый файл рассматривать как блок пямяти с произвольным доступом (все записи и чтения байта по адресу, лежащему в пределах такого блока, приводят к изменению соотв. байта в файле). Это может быть очень удобно, когда необходимо работать с файлами очень большого объема: вместо того, чтобы читать всё содержимое файла в память (или искать нужный фрагмент функцией Seek), можно спроецировать файл на память и сразу прочитать или модифицировать нужный фрагмент памяти. Windows подгружает спроецированный файл постранично, по мере обращения к тем или иным адресам памяти; всё делается автоматически, на уровне механизма виртуальной памяти Win32, что избавляет от необходимости вручную следить за подгрузкой из файла или записью в файл ненужных участков памяти.

Пример на MFC:
Чтобы упростить себе жизнь, создадим простой класс на основе CFile (класс-предок будет заниматься открытием и закрытием файлов; нам же останется только реализовать в нашем классе пару функций для проецирования файла):
Код
 class CMemoryMappedFile: public CFile
{
protected:
     HANDLE m_hMapping;     // хэндл объекта "проекция файла"
     void *m_bufMapping;      // стартовый адрес проекции

public:   // набор конструкторов
     CMemoryMappedFile() {m_hMapping=NULL;}
     CMemoryMappedFile(char *strFileName, UINT openFlags): CFile(strFileName, openFlags) {m_hMapping=NULL;}
     ~CMemoryMappedFile() {if(m_hMapping) ReleaseMemoryMapping();}

public:  // пара функций "спроецировать" / "освободить проекцию"
     void *GetMemoryMapping(bool bReadOnly=false);
     void ReleaseMemoryMapping();
};



// функция проецирует файл на память (файл должен быть уже открыт)
// и возвращает стартовый адрес блока памяти
void *CMemoryMappedFile::[b]GetMemoryMapping(bool bReadOnly)[/b]
{
     if(!m_hFile || m_hMapping) return NULL;
     m_hMapping = CreateFileMapping((void*)m_hFile, 0, bReadOnly?PAGE_READONLY:PAGE_READWRITE, 0, 0, 0);
     if(!m_hMapping) return NULL;
     m_bufMapping = MapViewOfFile(m_hMapping, FILE_MAP_READ|(bReadOnly?0:FILE_MAP_WRITE), 0, 0, 0);
     if(!m_bufMapping) CloseHandle(m_hMapping);
     return m_bufMapping;
}


// освобождение проекции
void CMemoryMappedFile::[b]ReleaseMemoryMapping[/b]()
{
     if(!m_hMapping) return;
     UnmapViewOfFile(m_bufMapping);
     CloseHandle(m_hMapping);
     m_hMapping = NULL;
}

// ===============================================

// пример - создадим текстовый файл на диске С: и запишем
// в него строку текста, затем заменим третий символ на "Z":
void DemoFileMapping()
{
     CMemoryMappedFile file("c:\\1.txt", CFile::modeCreate|CFile::modeReadWrite);
     char *str = "ABCDEFG";
     file.Write(str, strlen(str));

     char *buf = (char*)file.GetMemoryMapping();
     buf[2] = 'Z';
     file.ReleaseMemoryMapping();
}



Пример на "чистом" WinAPI:
Код
// пример - создадим текстовый файл на диске С: и запишем
// в него строку текста, затем заменим третий символ на "Z":
void  DemoFileMapping()
{
     HANDLE hFile = CreateFile ( "c:\\1.txt", GENERIC_READ | GENERIC_WRITE,
          FILE_SHARE_READ|FILE_SHARE_WRITE,
          NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
     
     DWORD d; 
     char *str = "ABCDEFG";
     WriteFile(hFile, str, strlen(str), &d, 0);
    
     HANDLE mapping = CreateFileMapping(hFile, 0, PAGE_READWRITE, 0, 0, 0);
     if(mapping)
     {
          char *buf = (char *)MapViewOfFile(mapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);
          if(buf)
          {
               buf[2] = 'Z';
               UnmapViewOfFile(buf);
          }
          CloseHandle(mapping);
     }
     CloseHandle(hFile);
}
 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)