Отображение файлов в память
Материал из DRKB
Отображение файлов в память
Для работы с файлом динамической подкачки страниц виртуальной памяти в Windows 32 используется механизм отображения файлов в адресное пространство программы. Соответствующие функции API доступны любой программе и могут применяться к любому файлу (кстати, таким способом загружается в адресное пространство процесса исполняемый файл). В результате отображения программа может работать с файловыми данными как с данными, размещенными в динамической памяти. Такая возможность не только в большинстве случаев повышает скорость работы с данными, но и предоставляет программисту уникальные средства обработки сразу всех записей файла. Например, он может единственным оператором проверить входит ли заданный образец поиска в любую строку текстового файла. Отображение файла осуществляется в три приема.
Создание/открытие файла[править | править код]
Вначале файл создается обращением к функции
function FileCreate(FileName: String): Integer;
или открывается с помощью
function FileOpen(const FileName: String; Mode: LongWord): Integer;
В обеих функциях FileName - имя файла, возможно, с маршрутом доступа. Параметр Mode определяет режим доступа к файлу и может принимать одно из следующих значений:
- fmOpenRead - только чтение;
- fmOpenWrite - только Запись;
- fmOpenReadWrite - чтение и запись.
C помощью операции or
эти константы можно комбинировать с одной из следующих регулирующих совместный доступ к файлу нескольких Программ:
- fmShareExclusive - совместный доступ Запрещен;
- fmShareDenyWrite - Другим Программам запрещается запись;
- fmShareDenyRead - другим программам запрещается чтение;
- fmSchareDenyNone - совместный доступ неограничен.
Обе функции возвращают дескриптор созданного (открытого) файла или 0, если операция оказалась неуспешной.
Создание объекта отображения[править | править код]
На втором этапе создается объект отображения в память. Для этого используется такая функция:
function CreateFileMapping(hFile: THandle; IpFileMappingAttributes: PSecurityAttributes;
flProtect, dwMaximumSizeHigh, dwMaximumSizeLow: DWord; IpName: PChar): THandle;
- hFile - дескриптор файла;
- ipFileMappingAttributes - указатель на структуру, в которой определяется, может ли создаваемый объект порождать дочерние объекты (обычно не может - nil);
- flProtect - определяет тип защиты, применяемый к окну отображения файла (см.ниже);
- dwMaximumSizeHigh, dwMaximumSizeLow - соответственно Старшие и младшие 32 разряда размера файла; если вы будете отображать файлы длинной до 4 ГбаЙТ, поместите В dwMaximumSizeHigh 0, а В dwMaximumSizeLow - длину файла; если оба параметра равны 0, размер окна отображения равен размеру файла;
- ipName - имя объекта отображения или 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(IpBaseAddress: Pointer): BOOL;
единственный параметр обращения к которой должен содержать адрес первого отображенного байта, т. е. адрес, возвращаемый функцией MapViewOfFile
. Закрытие объекта отображения и самого файла осуществляется обращением к функции
function CloseHandle(hObject: THandle)
Пример использования[править | править код]
Программа создает дисковый файл, состоящий из 100000 случайных вещественных чисел (длину файла можно выбрать другой, если изменить значение редактора длина массива). Файл с именем test.dat создается путем отображения файла в память (кнопка память) и традиционным способом (кнопка Файл). В обоих случаях показывается время счета (процессор 400 МГц, память 64 Мбайт). Чем больше частота и память, тем больше будет разница во времени.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls, Spin;
type
TFormI = class (TForm)
btMem: TButton;
btFile: TButton;
se: TSpinEdit;
Labell: TLabel;
pb: TProgressBar;
Label2: TLabel;
IbMem: TLabel;
IbFile: 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, О, О, 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));
IbMem.Caption := IntToStr(k);
pb.Position := k;
Application.ProcessMessages;
end;
// Освобождаем окно просмотра:
UnmapViewOfFile(AdrBase)
finally
// Освобождаем отображение
CloseHandle(HMap);
end;
finally
// Закрываем файл
CloseHandle(HFile);
end;
// Сообщаем время счета
pb.Hide;
IbMem.Caption := TimeToStr(Time - BegTime);
end;
// Создание файла обычным методом var
procedure TFormI.btFileClick(Sender: TObject) ;
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); // могут быть только переменные
IbFile.Caption := IntToStr(k);
pb.Position := k;
Application.ProcessMessages;
end;
CloseFile(F) ;
pb.Hide;
IbFile.Caption := TimeToStr(Time - BegTime)
end;
end.
ID: 03123
ID: 03134