Отображение файла в память для совместного использования несколькими процессами.
Первый процесс создает файл Temp.txt, после чего проецирует его в память
//первый процесс
unit mainServ;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
btnCreate: TButton;
Memo1: TMemo;
procedure btnCreateClick(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ Private declarations }
public
{ Public declarations }
end;
const
MMFName: PWideChar = 'DelphiFileMappedExample'; // имя объекта файлового отображения
bufSize=100;//размер буфера
var
Form1: TForm1;
hFile,hMapedFile:HWND;
pMapFile:Pointer;
implementation
{$R *.dfm}
//Создание именованной, совместно используемой памяти
procedure TForm1.btnCreateClick(Sender: TObject);
var
outBuff:array[0..bufSize] of Char;
byteWrt:Cardinal;
begin
if not Assigned(pMapFile) then
UnmapViewOfFile(pMapFile);
if hMapedFile<>INVALID_HANDLE_VALUE then
CloseHandle(hMapedFile);
if (hFile<>INVALID_HANDLE_VALUE) then
CloseHandle(hFile);
hFile:=CreateFile(PWideChar('Temp.txt'),
GENERIC_READ or GENERIC_WRITE,
FILE_SHARE_READ or FILE_SHARE_WRITE,
nil,CREATE_ALWAYS or OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,0);
if hFile=INVALID_HANDLE_VALUE then
begin
ShowMessage('Ошибка при создании файла '+SysErrorMessage(GetLastError));
Exit;
end;
StrPCopy(outBuff,Memo1.Lines.Text);
WriteFile(hFile,outBuff,bufSize*SizeOf(Char),byteWrt,nil);
hMapedFile:=CreateFileMapping(hFile, //INVALID_HANDLE_VALUE-использование файла подкачки
nil, // защита по умолчанию
PAGE_READWRITE, //доступ к чтению/записи
0, // макс. размер объекта
bufSize*SizeOf(Char), // размер буфера
MMFName); // имя отраженного в памяти объекта
if hMapedFile=INVALID_HANDLE_VALUE then
begin
ShowMessage('Ошибка при проецировании файла в память '+SysErrorMessage(GetLastError));
CloseHandle(hFile);
Exit;
end;
pMapFile:=MapViewOfFile(hMapedFile, //дескриптор "проецируемого" объекта
FILE_MAP_ALL_ACCESS, // разрешение чтения/записи
0,0,
bufSize*SizeOf(Char));//размер буфера
if pMapFile=nil then
begin
ShowMessage('Ошибка при отображении файла '+SysErrorMessage(GetLastError));
CloseHandle(hMapedFile);
CloseHandle(hFile);
Exit;
end;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if not Assigned(pMapFile) then
UnmapViewOfFile(pMapFile);
if hMapedFile<>INVALID_HANDLE_VALUE then
CloseHandle(hMapedFile);
if (hFile<>INVALID_HANDLE_VALUE) then
CloseHandle(hFile);end;
end.
Когда процессу больше не нужен доступ к объекту "проекция файла в память", он должен вызвать функцию CloseHandle. Когда все дескрипторы закрыты, система может освободить секцию файла подкачки, используемого объектом.
Второй процесс может получить доступ к одним и тем же данным при помощи вызова функции OpenFileMapping с тем же самым именем, что и первый процесс. Он может затем использовать функцию MapViewOfFile, чтобы получить указатель на представление данных файла.
//второй процесс
unit clientMain;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
btnRead: TButton;
Memo1: TMemo;
procedure btnReadClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
const
MMFName: PWideChar = 'DelphiFileMappedExample'; // имя объекта файлового отображения
bufSize=100;//размер буфера
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.btnReadClick(Sender: TObject);
var
hMapedFile:HWND;
pMapFile:Pointer;
begin
hMapedFile:=OpenFileMapping(FILE_MAP_ALL_ACCESS, // доступ к чтению/записи
False, //имя не наследуется
MMFName);//имя "проецируемого " объекта
if hMapedFile=INVALID_HANDLE_VALUE then
begin
ShowMessage('Ошибка при проецировании файла в память '+SysErrorMessage(GetLastError));
Exit;
end;
pMapFile:=MapViewOfFile(hMapedFile,//дескриптор "проецируемого" объекта
FILE_MAP_ALL_ACCESS,// разрешение чтения/записи
0,0,
bufSize*SizeOf(Char));//размер буфера
if pMapFile=nil then
begin
ShowMessage('Ошибка при отображении файла '+SysErrorMessage(GetLastError));
CloseHandle(hMapedFile);
Exit;
end;
Memo1.Text:=PChar(pMapFile);
UnmapViewOfFile(pMapFile);
CloseHandle(hMapedFile);
end;
end.
Когда процессу больше не нужен доступ к объекту "проекция файла в память", он должен вызвать функцию CloseHandle. Когда все дескрипторы закрыты, система может освободить секцию файла подкачки, используемого объектом.
Скачать проекты можно отсюда Download
Первый процесс создает файл Temp.txt, после чего проецирует его в память
//первый процесс
unit mainServ;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
btnCreate: TButton;
Memo1: TMemo;
procedure btnCreateClick(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ Private declarations }
public
{ Public declarations }
end;
const
MMFName: PWideChar = 'DelphiFileMappedExample'; // имя объекта файлового отображения
bufSize=100;//размер буфера
var
Form1: TForm1;
hFile,hMapedFile:HWND;
pMapFile:Pointer;
implementation
{$R *.dfm}
//Создание именованной, совместно используемой памяти
procedure TForm1.btnCreateClick(Sender: TObject);
var
outBuff:array[0..bufSize] of Char;
byteWrt:Cardinal;
begin
if not Assigned(pMapFile) then
UnmapViewOfFile(pMapFile);
if hMapedFile<>INVALID_HANDLE_VALUE then
CloseHandle(hMapedFile);
if (hFile<>INVALID_HANDLE_VALUE) then
CloseHandle(hFile);
hFile:=CreateFile(PWideChar('Temp.txt'),
GENERIC_READ or GENERIC_WRITE,
FILE_SHARE_READ or FILE_SHARE_WRITE,
nil,CREATE_ALWAYS or OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,0);
if hFile=INVALID_HANDLE_VALUE then
begin
ShowMessage('Ошибка при создании файла '+SysErrorMessage(GetLastError));
Exit;
end;
StrPCopy(outBuff,Memo1.Lines.Text);
WriteFile(hFile,outBuff,bufSize*SizeOf(Char),byteWrt,nil);
hMapedFile:=CreateFileMapping(hFile, //INVALID_HANDLE_VALUE-использование файла подкачки
nil, // защита по умолчанию
PAGE_READWRITE, //доступ к чтению/записи
0, // макс. размер объекта
bufSize*SizeOf(Char), // размер буфера
MMFName); // имя отраженного в памяти объекта
if hMapedFile=INVALID_HANDLE_VALUE then
begin
ShowMessage('Ошибка при проецировании файла в память '+SysErrorMessage(GetLastError));
CloseHandle(hFile);
Exit;
end;
pMapFile:=MapViewOfFile(hMapedFile, //дескриптор "проецируемого" объекта
FILE_MAP_ALL_ACCESS, // разрешение чтения/записи
0,0,
bufSize*SizeOf(Char));//размер буфера
if pMapFile=nil then
begin
ShowMessage('Ошибка при отображении файла '+SysErrorMessage(GetLastError));
CloseHandle(hMapedFile);
CloseHandle(hFile);
Exit;
end;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if not Assigned(pMapFile) then
UnmapViewOfFile(pMapFile);
if hMapedFile<>INVALID_HANDLE_VALUE then
CloseHandle(hMapedFile);
if (hFile<>INVALID_HANDLE_VALUE) then
CloseHandle(hFile);end;
end.
Когда процессу больше не нужен доступ к объекту "проекция файла в память", он должен вызвать функцию CloseHandle. Когда все дескрипторы закрыты, система может освободить секцию файла подкачки, используемого объектом.
Второй процесс может получить доступ к одним и тем же данным при помощи вызова функции OpenFileMapping с тем же самым именем, что и первый процесс. Он может затем использовать функцию MapViewOfFile, чтобы получить указатель на представление данных файла.
//второй процесс
unit clientMain;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
btnRead: TButton;
Memo1: TMemo;
procedure btnReadClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
const
MMFName: PWideChar = 'DelphiFileMappedExample'; // имя объекта файлового отображения
bufSize=100;//размер буфера
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.btnReadClick(Sender: TObject);
var
hMapedFile:HWND;
pMapFile:Pointer;
begin
hMapedFile:=OpenFileMapping(FILE_MAP_ALL_ACCESS, // доступ к чтению/записи
False, //имя не наследуется
MMFName);//имя "проецируемого " объекта
if hMapedFile=INVALID_HANDLE_VALUE then
begin
ShowMessage('Ошибка при проецировании файла в память '+SysErrorMessage(GetLastError));
Exit;
end;
pMapFile:=MapViewOfFile(hMapedFile,//дескриптор "проецируемого" объекта
FILE_MAP_ALL_ACCESS,// разрешение чтения/записи
0,0,
bufSize*SizeOf(Char));//размер буфера
if pMapFile=nil then
begin
ShowMessage('Ошибка при отображении файла '+SysErrorMessage(GetLastError));
CloseHandle(hMapedFile);
Exit;
end;
Memo1.Text:=PChar(pMapFile);
UnmapViewOfFile(pMapFile);
CloseHandle(hMapedFile);
end;
end.
Когда процессу больше не нужен доступ к объекту "проекция файла в память", он должен вызвать функцию CloseHandle. Когда все дескрипторы закрыты, система может освободить секцию файла подкачки, используемого объектом.
Скачать проекты можно отсюда Download
В проекте используется локальное кеширование метаданных из БД в ini-файл. Работа с файлом происходит через обьект TCustomIniFile. Все работает быстро и красиво. Но до того момента, когда приложений несколько. Проблемы начинаются, когда через терминальный сервер подключаются десятки\сотни клиентов. Происходит неоптимальное выжирание памяти. Фактически, каждый екземпляр приложения вычитывает и кеширует одинаковый набор ini-файлов. Можна ли при помощи проекции файла в память реализовать работу с общим кешем? Или как можно организовать работу кеша, чтобы повторно использовать обьект/данные другими приложениями без ущерба производительности?
ОтветитьУдалитьсначала не понял смысла вопроса долго вчитывался.
Удалитьпосмотрев MSDN нашел следующее:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa366551%28v=vs.85%29.aspx
Предваряя файл сопоставления имен объектов с «Global\» позволяет процессам взаимодействовать друг с другом, даже если они находятся в различных терминальных сеансах сервера. Это требует, что первый процесс должен иметь привилегии SeCreateGlobalPrivilege.
как я понял это то, что вам нужно!