Отображение файла в память

Для работы с файлом динамической подкачки страниц виртуальной памяти в Windows 32 используется механизм отображения файлов в адресное пространство приложения. Соответствующие функции API доступны любому приложению и могут применяться к любому файлу (кстати, таким способом загружаются в адресное пространство процесса исполняемые файлы и DLL). В результате отображения приложение может работать с файловыми данными как с размещенными в динамической памяти. В большинстве случаев такая возможность не только повышает скорость работы с данными, но и предоставляет программисту уникальные средства обработки сразу всех записей файла. Например, он может с помощью единственного оператора проверить, входит ли заданный образец поиска в какую-либо строку текстового файла.

Отображение файла осуществляется в три приема. Вначале файл создается обращением к функции:
function FileCreate (FileName: String): Integer;

или открывается с помощью:
function FileOpen (const FileName: String; Mode: LongWord): Integer;

В обеих функциях FileName — имя файла, возможно, с маршрутом доступа. Параметр Mode определяет режим доступа к файлу и может принимать одно из следующих значений: fmOpenRead — только чтение; fmOpenWrite — только запись; fmOpenReadWrite — чтение и запись. С помощью операции or эти константы можно комбинировать с одной из следующих нескольких функций, регулирующих совместный доступ к файлу: fmShareExclusive — совместный доступ запрещен; fmShareDenyWrite — другим приложениям запрещается запись; fmShareDenyRead — другим приложениям запрещается чтение; fmSchareDenyNone — совместный доступ неограничен. Обе функции возвращают дескриптор созданного (открытого) файла или 0, если операция оказалась неудачной.

На втором этапе создается объект отображения в память. Для этого используется функция:
function CreateFileMapping (hFile: THandle; lpFileMappingAttributes: PSecurityAttributes; flProtect, dwMaximumSizeHigh, dwMaximumSizeLow: DWord; lpName: PChar): THandle;

Здесь hFile — дескриптор файла; lpFileMappingAttributes — указатель на структуру, в которой определяется, может ли создаваемый объект порождать дочерние объекты (обычно не может — NIL); flProtect — определяет тип защиты, применяемый к окну отображения файла (см. об этом ниже); dwMaximumSizeHigh, dwMaximumSizeLow — соответственно старшие и младшие 32 разряда числа, содержащего размер файла (если вы будете отображать файлы длиной до 4 Гбайт, поместите в dwMaximumSizeHigh 0, если в dwMaximumSizeLow — длину файла; а если оба параметра равны 0, то размер окна отображения равен размеру файла); lpName — имя объекта отображения или NIL.

Параметр flProtect задает тип защиты, применяемый к окну просмотра файла, и может иметь одно из следующих значений: PAGE_READONLY — файл можно только читать (файл должен быть создан или открыт в режиме fmOpenRead); PAGE_READWRITE — файл можно читать и записывать в него новые данные (файл открывается в режиме fmOpenReadWrite); PAGE_WRITECOPY — файл открыт для записи и чтения, однако обновленные данные сохраняются в отдельной защищенной области памяти (отображенные файлы могут разделяться приложениями, в этом режиме каждое приложение сохраняет изменения в отдельной области памяти или участке файла подкачки); файл открывается в режиме fmOpenReadWrite или fmOpenWrite; (этот тип защиты нельзя использовать в Windows 95/98). С помощью операции or к параметру flProtect можно присоединить такие атрибуты: SEC_COMMIT — выделяет для отображения физическую память или участок файла подкачки; SEC_IMAGE — информация об атрибутах отображения берется из образа файла; SEC_NOCASHE — отображаемые данные не кэшируются и записываются непосредственно на диск; SEC_RESERVE — резервируются страницы раздела без выделения физической памяти.

Функция возвращает дескриптор объекта отображения или 0, если обращение было неудачным.

Наконец, на третьем этапе создается окно просмотра, то есть собственно отображение данных в адресное пространство программы.
function MapViewOfFile(hFileMappingObject:   
THandle;dwDesiresAccess: DWord; dwFileOffsetHigh, dwFileIffsetLow,   
dwNumberOfBytesToMap: DWord): Pointer;

Здесь hFileMappingObject — дескриптор объекта отображения; dwDesiresAccess — определяет способ доступа к данным и может иметь одно из следующих значений: FILE_MAP_WRITE — разрешает чтение и запись (при этом в функции CreateFileMapping должен использоваться атрибут PAGE_READWRITE); FILE_MAP_READ — разрешает только чтение (в функции CreateFileMapping должен использоваться атрибут PAGE_READONLY или PAGE_READWRITE); FILE_MAP_ALL_ACCESS — то же, что и FILE_MAP_WRITE; FILE_MAP_COPY — данные доступны для записи и чтения, однако обновленные данные сохраняются в отдельной защищенной области памяти (в функции CreateFileMapping должен использоваться атрибут PAGE_WRITECOPY); dwFileOffsetHigh, dwFileIffsetLow — определяют соответственно старшие и младшие разряды смещения от начала файла, начиная с которого осуществляется отображение; dwNumberOfBytesToMap — определяет длину окна отображения (0 — длина равна длине файла). Функция возвращает указатель на первый байт отображенных данных или NIL, если обращение к функции оказалось безуспешным.

После использования отображенных данных ресурсы окна отображения нужно освободить функцией:
function UnMapViewOfFile(lpBaseAddress: Pointer): BOOL;

единственный параметр обращения к которой должен содержать адрес первого отображенного байта, то есть адрес, возвращаемый функцией MapViewOfFile. Закрытие объекта отображения и самого файла осуществляется обращением к функции:
function CloseHandle(hObject: THandle)

В листинге 3 приводится текст модуля (FileInMemory.dpr), который создает окно.

Листинг 3
unit Unit1;   
    
interface   
    
uses   
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,    StdCtrls, ComCtrls, Spin;   
    
type   
  TForm1 = class(TForm)   
    btMem: TButton;   
    btFile: TButton;   
    se: TSpinEdit;   
    Label1: TLabel;   
    pb: TProgressBar;   
    Label2: TLabel;   
    lbMem: TLabel;   
    lbFile: TLabel;   
    procedure btMemClick(Sender: TObject);   
    procedure btFileClick(Sender: TObject);   
  private   
    { Private declarations }   
  public   
    { Public declarations }   
  end;   
    
var   
  Form1: TForm1;   
    
implementation   
    
{$R *.DFM}   
    
    
procedure TForm1.btMemClick(Sender: TObject);   
// Создание файла методом его отображения   
type   
  PReal = ^Real;   
var   
  HFile, HMap: THandle;   
  AdrBase, AdrReal: PReal;   
  k: Integer;   
  FSize: Cardinal;   
  BegTime: TDateTime;   
begin   
  BegTime := Time;   // Засекаем время пуска   
  // Готовим ProgressBar:   
  pb.Max := se.Value;   
  pb.Position := 0;   
  pb.Show;   
  FSize := se.Value * SizeOf(Real); // Длина файла    
  HFile := FileCreate('test.dat');  // Создаем файл      
  if HFile = 0 then     // Ошибка:    возбуждаем исключение   
    raise Exception.Create('Ошибка создания файла');    
  try   
    // Отображаем файл в память   
    HMap := CreateFileMapping(   
HFile, NIL, PAGE_READWRITE, 0, FSize, NIL);   
    if HMap = 0 then    // Ошибка:    возбуждаем исключение   
      raise Exception.Create('Ошибка отображения    файла');   
    try   
      // Создаем окно просмотра:   
      AdrBase := MapViewOfFile(HMap, FILE_MAP_WRITE,    0, 0, FSize);   
      if AdrBase = NIL then  //    Ошибка: возбуждаем исключение   
        raise Exception.Create('Невозможно    просмотреть файл');   
      // Сохраняем начальный адрес для правильной    ликвидации   
      // окна просмотра:   
      AdrReal := AdrBase;   
      for k := 1 to se.Value do   
      begin   
        AdrReal^ := Random;  //    Помещаем в файл новое число   
        // Перед наращиванием текущего    адреса необходимо   
        // привести его к типу Integer    или Cardinal:   
        AdrReal := Pointer(Integer(AdrReal)    + SizeOf(Real));   
        lbMem.Caption := IntToStr(k);   
        pb.Position := k;   
        Application.ProcessMessages;   
      end;   
      // Освобождаем окно просмотра:   
      UnmapViewOfFile(AdrBase)   
    finally   
      // Освобождаем отображение   
      CloseHandle(HMap)   
    end   
  finally   
    // Закрываем файл   
    CloseHandle(HFile)   
  end;   
  // Сообщаем время счета   
  pb.Hide;   
  lbMem.Caption := TimeToStr(Time-BegTime)   
end;   
    
procedure TForm1.btFileClick(Sender: TObject);   
// Создание файла обычным методом   
var   
  F: File of Real;   
  k: Integer;   
  BegTime: TDateTime;   
  R: Real;   // Буферная переменная для обращения к Write    
begin   
  BegTime := Time;  // Засекаем начальное время счета   
  // Готовим ProgressBar:   
  pb.Max := se.Value;   
  pb.Position := 0;   
  pb.Show;   
  // Создаем файл:   
  AssignFile(F, 'test.dat');   
  Rewrite(F);   
  for k := 1 to se.Value do   
  begin   
    R := Random;   // Параметрами обращения к Write    
    Write(F, R);   // могут быть только переменные    
    lbFile.Caption := IntToStr(k);   
    pb.Position := k;   
    Application.ProcessMessages;   
  end;   
  CloseFile(F);   
  pb.Hide;   
  lbFile.Caption := TimeToStr(Time-BegTime)   
end;   
    
end.

Проект создает дисковый файл, состоящий из 100 тыс. случайных вещественных чисел (можно выбрать другую длину файла, если изменить значение редактора Длина массива). Файл с именем test.dat создается путем отображения файла в память (кнопка Память) и традиционным способом (кнопка Файл). В обоих случаях показывается время счета. Чем больше частота процессора и объем свободной оперативной памяти, тем больше будет разница во времени (листинг 3).
Теги:
Отображение файла, память
Добавлено: 08 Апреля 2018 06:49:22 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...