Создание представления внутри файла


Если вы хотите представить часть файла, которая начинается не в начале файла, вам нужно создать объект "проекция файла". Величина этого объекта равняется величине части файла, которую вы желаете представить, плюс смещение внутри файла.  Например, если вы хотите представить 1 килобайт (1K) данных, которые начинаются в файле от 131 072 байта (128K), вы должны создать  объект "проекция файла", по крайней мере, величиной 132,096 байтов (129K). Представление данных в файле должно начинаться с 131 072 байта (128K)  и тянуться, по крайней мере, 1 024 байтов. В этом примере предполагается 64 КБ гранулярность выделения ресурсов файла.

Гранулярность выделения ресурсов файла находится под влиянием того, где  может начаться представление проецированных данных. Представление проецирования должно начаться в файле при смещении, которое является кратным  назначенной гранулярности файла. Так что данные, которые Вы хотите представить, должны иметь смещение по модулю  гранулярности для представления в файле. Размер представления  данных должен быть равен смещению по модулю гранулярности данных, плюс размер данных, которые Вы хотите проверить.

Если Вы хотите проверить 1 КБ данных смещенных в файле на 138 240 байтов (135 КБ), предполагая, что функция GetSystemInfo указывает гранулярность выделения ресурсов 64 КБ, Вы должны сделать следующее:

  1. Создать объект "проецируемый файл" по крайней мере величиной 139 264 байта (136 КБ) .
  2. Создать представление файла, начинающееся при смещении  в файле, которое является наибольшим кратным гранулярности, но меньше, чем смещение, которое Вы требуете. В этом случае, представление данных файла начнется при смещении в файле равным 131 072 (128 КБ) . Представление должно быть 139 264 байтов (136 КБ) минус 131 072 байта (128 КБ), или по величине 8 192 байта (8 КБ).
  3. Создать в представлении смещение указателя на 7 КБ , чтобы получить доступ к 1 КБ данных, которыми Вы заинтересовались.

Если данные, которые Вам нужны, широко разбросаны между границ гранулярности выделения ресурсов файла, Вы можете сделать представление данных большим, чем гранулярность. Это поможет избежать дробления данных на кусочки.

Нижеследующая программа иллюстрирует второй пример выше.

/* filemap.c,

   Эта программа демонстрирует проецируемый в память файл,
   особенно как выравнивать представление данных
   с системной гранулярностью выделения ресурсов файлу. */

#include <windows.h>

#define BUFFSIZE 1024         // размер памяти для проверки
                              // в любой момент

#define FILE_MAP_START 138240 // стартовая точка внутри файла
                              // проверяемых данных (135K)


/* Проверка файла. Код ниже создает файл и заполняет его, так что
 нет необходимости делать это заранее. */

char * lpcTheFile = "fmtest.txt"; // файл, который обрабатывается


int main(void)
{
  HANDLE hMapFile;      // дескриптор отображаемой в памяти
                        // области проверяемого файла
  HANDLE hFile;         // дескриптор файла
  BOOL bFlag;           // фиксатор результата
  DWORD dBytesWritten;  // записанное число байтов
  DWORD dwFileSize;     // временное сохранение размеров файла
  DWORD dwFileMapSize;  // размер отображения файла в память
  DWORD dwMapViewSize;  // размер представления данных
  DWORD dwFileMapStart; // где в файле начало представления
                        // проецирования файла
  DWORD dwSysGran;      // системная гранулярность
                        // выделения ресурсов
  SYSTEM_INFO SysInfo;  // системная информация; используется
                        // для получения гранулярности
  LPVOID lpMapAddress;  // указатель на базовый адрес отображаемой
                        // в памяти области
  char * pData;         // указатель на данные
  int i;                // счетчик циклов
  int iData;            // первый int данных, если
                        // все идет правильно
  int iViewDelta;       // смещение в представлении,
                        // где обнаруживаются данные
  int iRet;             // возвращаемое значение

  // Создайте проверяемый файл. Откроем его как "Create Always", 
  // чтобы переписывать любой существующий файл.
  // Данные обновляются ниже.
  hFile = CreateFile(lpcTheFile, GENERIC_READ | GENERIC_WRITE,
          0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

  if (hFile == INVALID_HANDLE_VALUE)
  {
    printf("hFile is NULL\n");
    printf("Target file is %s\n", lpcTheFile);
    return 4;
  }

  // Получите системную гранулярность выделения ресурсов.
  GetSystemInfo(&SysInfo);
  dwSysGran = SysInfo.dwAllocationGranularity;

  // Теперь вычислите несколько переменных. Вычислите смещения
  // файла, как 64-битовое значение, а затем получите младшие 
  // 32 бита для вызовов функции.

  // Чтобы вычислить, где начать отображение файла в память,
  // округлите в меньшую сторону смещение данных в файле к самому
  // близкому кратному системной гранулярности выделения ресурсов.

  dwFileMapStart = (FILE_MAP_START / dwSysGran) * dwSysGran;
  printf ("The file map view starts at %ld bytes into the file.\n",
          dwFileMapStart);

  // Вычислите размер представления проекции файла в память.

  dwMapViewSize = (FILE_MAP_START % dwSysGran) + BUFFSIZE;
  printf ("The file map view is %ld bytes large.\n", dwMapViewSize);

  // Какой величины будет объект "проекция файла"?

  dwFileMapSize = FILE_MAP_START + BUFFSIZE;
  printf ("The file mapping object is %ld bytes large.\n", dwFileMapSize);

  // Интересуемые данные не в начале представления, так что 
  // определите как далеко в представлении установлен указатель позиции.

  iViewDelta = FILE_MAP_START - dwFileMapStart;
  printf ("The data is %d bytes into the view.\n", iViewDelta);

  // Теперь запишите файл данные, подходящие для эксперимента. Они
  // дают уникальные int (4-байтовые) смещения в файле для 
  // облегчения визуального контроля.  Обратите внимание! на то, 
  // что этот код не проверяет переполнение носителя данных
  // или другие ошибки, которые может сделать созданный код.
  // Поскольку int равно 4 байтам, значение в указателе на данные 
  // должно быть 1/4 требуемого смещения в файле.

  for (i=0;i<2*dwSysGran;i++) 
  {
    WriteFile (hFile, &i, sizeof (i), &dBytesWritten, NULL);
  }

  // Проверьте, что записался правильный размер файла.
  dwFileSize = GetFileSize(hFile,  NULL);
  printf("hFile size: %10d\n", dwFileSize);

  // Создайте объект "проекция файла" для файла.
  hMapFile = CreateFileMapping( hFile, // текущий дескриптор файла
                                NULL,  // защита по умолчанию
                                PAGE_READWRITE, // разрешение 
                                                // чтения - записи
                                0,  // размер "проецируемого"
                                    // объекта, максимум
                                dwFileMapSize,// размер "проецируемого"
                                              // объекта, минимум
                                NULL); // имя проецируемого объекта

  if (hMapFile == NULL) {
    printf("hMapFile is NULL: last error: %d\n", GetLastError() );
    return (2);
  }

  // Проецируйте представление и проверьте результаты.

  lpMapAddress = MapViewOfFile(hMapFile, // дескриптор проецируемого
                                         // объекта
                               FILE_MAP_ALL_ACCESS, // разрешение 
                                                  // чтения/записи
                               0,               // старшие 32 бита
                                               // смещения в файле
                               dwFileMapStart,  // младшие 32 бита
                                               // смещения в файле
                               dwMapViewSize); // число отображаемых
                                               // байтов
  if (lpMapAddress == NULL) {
    printf("lpMapAddress is NULL: last error: %d\n", GetLastError());
    return 3;
  }

  // Вычислите указатель на данные.
  pData = (char *) lpMapAddress + iViewDelta;

//    dump((char *)pData, BUFFSIZE);

  // Извлеките данные, int. Приведите указатель pData из "указатель
  // на символ" в "указатель на int", чтобы получить все это.
  iData = *(int *)pData;

  printf ("The value at the pointer is %d,\nwhich %s
           one quarter of the desired file offset.\n",
          iData,
          iData*4 == FILE_MAP_START ? "is" : "is not");

  // Закройте объект "проекция файла" и открытый файл.

  bFlag = CloseHandle(hMapFile); // закройте объект "проекция файла"

  if(!bFlag) {
    printf("\nOops! Error # %ld occurred closing the mapping object!",
           GetLastError());
  }

  bFlag = CloseHandle(hFile);   // закройте файл непосредственно

  if(!bFlag) {
    printf("\nOops! Error # %ld occurred closing the file!",
           GetLastError());
  }

  return 0;

}

 

Назад в оглавление темы
На главную страницу темы

Hosted by uCoz