Delphi - объектно-ориентированный язык программирования, разработанный компанией Borland в 1995 году. Он основан на языке программирования Pascal, но имеет более расширенные возможности и добавлены новые функции.
Delphi является интегрированной средой разработки (IDE), которая позволяет разрабатывать программное обеспечение для различных платформ, включая Windows, macOS, Android и iOS. Delphi достигает многоплатформенности с помощью...
unitSharedStream; interface
uses
SysUtils, Windows, Classes, Consts; type
{ TSharedStream } TSharedStream = class
(TStream)
{ Для совместимости с TStream } privateFMemory : Pointer;
{ Указатель на данные } FSize : Longint; { Реальный размер записанных данных } FPageSize : Longint; { Размер выделенной "страницы" под данные } FPosition : Longint; { Текущая позиция "курсора" на "странице" } protectedpublic
constructor
Create; destructor
Destroy; override
; function
Read
(var
Buffer; Count: Longint): Longint; override
; function
Write(const
Buffer; Count: Integer): Longint; override
; function
Seek(Offset: Longint; Origin: Word): Longint; override
; procedure
SetSize(NewSize: Longint); override
; procedure
LoadFromStream(Stream: TStream); procedure
LoadFromFile(const
FileName: string
); procedure
SaveToStream(Stream: TStream); procedure
SaveToFile(const
FileName: string
); public
property
Memory: Pointer read
FMemory; end
; const
SwapHandle = $FFFFFFFF;
{ Handle файла подкачки } implementationresourcestring
CouldNotMapViewOfFile = 'Could not map view of file.';
{ TSharedStream } { * TSharedStream работает правильно только с файлом подкачки, с обычным файлом проще и надежнее работать TFileStream'ом. * Для тех кто знаком с File Mapping Functions'ами : Класс TSharedStream не может использоваться для синхронизации(разделения) данных среди различных процессов(программ/приложений). [пояснения в конструкторе] * Класс TSharedStream можно рассматривать как альтернативу временным файлам (т.е. как замену TFileStream). Преимущество : а. Данные никто не сможет просмотреть. б. Страница, зарезервированная под данные, автомотически освобождается после уничтожения создавшего ее TSharedStream'а. * Класс TSharedStream можно рассматривать как альтернативу TMemoryStream. Преимущество : а. Не надо опасаться нехватки памяти при большом объеме записываемых данных. [случай когда физически нехватает места на диске здесь не рассматривается]. Известные проблемы: На данный момент таких не выявлено. Но есть одно НО. Я не знаю как поведет себя TSharedStream в результате нехватки места а. на диске б. в файле подкачки (т.е. в системе с ограниченным размером файла подкачки). } constructorTSharedStream.Create; const
Sz = 1024000;
{ Первоначальный размер страницы }{ взят с потолка } varSHandle : THandle; begin
FPosition := 0;
{ Позиция "курсора" } FSize := 0; { Размер данных } FPageSize := Sz; { Выделенная область под данные } { Создаем дескриптор объекта отображения данных. //эта формулировка взята из книги Проще сказать - создаем страницу под данные. //разрешите, я здесь и далее //буду употреблять более протые //информационные вставки. Все подробности по CreateFileMapping в Help'e. } SHandle := CreateFileMapping( SwapHandle, nil, PAGE_READWRITE, 0, Sz, nil
);
{ Создаем "страницу"} { Handle файла подкачки } { Задаем размер "страницы"[Sz]. Не может быть = нулю} { Имя "страницы" должно быть нулевым[nil]} { иначе Вам в последствии не удастся изменить размер "страницы". (Подробнее см. в TSharedStream.SetSize). * Для тех кто знаком с File Mapping Functions'ами : раз страница осталась неименованной, то Вам не удастся использовать ее для синхронизации(разделения) данных среди различных процессов(программ/приложений). [остальных недолжно волновать это отступление] } ifSHandle = 0 then
raise
Exception.Create(CouldNotMapViewOfFile);
{ ошибка - неудалось создать объект отображения[т.е. "страница" не создана и указатель на нее = 0]. Это может быть: Если Вы что-либо изменяли в конструкторе - a. Из-за ошибки в параметрах, передоваемых функции CreateFileMapping б. Если Sz <= 0 Если Вы ничего не изменяли - а. То такое бывает случается после исключительных ситуаций в OS или некорректной работы с FileMapping'ом в Вашей или чужой программе. Помогает перезагрузка виндуса } FMemory := MapViewOfFile(SHandle, FILE_MAP_WRITE, 0, 0, Sz); { Получаем указатель на данные } ifFMemory = nil
then
raise
Exception.Create(CouldNotMapViewOfFile);
{ Виндус наверно может взбрыкнуться и вернуть nil, но я таких ситуаций не встречал. естественно если на предыдущих дейсвиях не возникало ошибок и если переданы корректные параметры для функции MapViewOfFile() } CloseHandle(SHandle); end; destructor
TSharedStream.Destroy; begin
UnmapViewOfFile(FMemory);
{ закрываем страницу. если у Вас не фиксированный размер файла подкачки, то через пару минут вы должны увидеть уменьшение его размера. } inheritedDestroy; end
; function
TSharedStream.Read
(var
Buffer; Count: Longint): Longint; begin
{ Функция аналогичная TStream.Read(). Все пояснения по работе с ней см. в help'e. } if
Count > 0 then
begin
Result := FSize - FPosition; if
Result > 0 then
begin
if
Result > Count then
Result := Count; Move((PChar(FMemory) + FPosition)^, Buffer, Result); Inc(FPosition, Result); end
end
else
Result := 0 end
; function
TSharedStream.Write(const
Buffer; Count: Integer): Longint; var
I : Integer; begin
{ Функция аналогичная TStream.Write(). Все пояснения по работе с ней см. в help'e. } if
Count > 0 then
begin
I := FPosition + Count; if
FSize < I then
Size := I; System.Move(Buffer, (PChar(FMemory) + FPosition)^, Count); FPosition := I; Result := Count; end
else
Result := 0 end
; function
TSharedStream.Seek(Offset: Integer; Origin: Word): Longint; begin
{ Функция аналогичная TStream.Seek(). Все пояснения по работе с ней см. в help'e. } case
Origin of
soFromBeginning : FPosition := Offset; soFromCurrent : Inc(FPosition, Offset); soFromEnd : FPosition := FSize - Offset; end
; if
FPosition > FSize then
FPosition := FSize else
if
FPosition < 0 then
FPosition := 0; Result := FPosition; end
; procedure
TSharedStream.SetSize(NewSize: Integer); const
Sz = 1024000; var
NewSz : Integer; SHandle : THandle; SMemory : Pointer; begin
{ Функция аналогичная TStream.SetSize(). Все пояснения по работе с ней см. в help'e. } inherited
SetSize(NewSize); if
NewSize > FPageSize then
{ Если размер необходимый для записи данных больше размера выделенного под "страницу", то мы должны увеличить размер "страницы", но... } begin
{ ...но FileMapping не поддерживает изменения размеров "страницы", что не очень удобно, поэтому приходится выкручиваться. } NewSz := NewSize + Sz; { задаем размер страницы + 1Meтр[чтобы уменьшить работу со страницами]. } { Создаем новую страницу }{ возможные ошибки создания страницы описаны в конструкторе TSharedStream. } SHandle := CreateFileMapping( SwapHandle, nil
, PAGE_READWRITE, 0, NewSz, nil
); if
SHandle = 0 then
raise
Exception.Create(CouldNotMapViewOfFile); SMemory := MapViewOfFile(SHandle, FILE_MAP_WRITE, 0, 0, NewSz); if
SMemory = nil
then
raise
Exception.Create(CouldNotMapViewOfFile); CloseHandle(SHandle); Move(FMemory^, SMemory^, FSize);
{ Перемещаем данные из старой "страницы" в новую } UnmapViewOfFile(FMemory); { Закрываем старую "страницу" } FMemory := SMemory; FPageSize := NewSz; { Запоминаем размер "страницы" } end; FSize := NewSize;
{ Запоминаем размер данных } ifFPosition > FSize then
FPosition := FSize; end
; procedure
TSharedStream.LoadFromFile(const
FileName: string
); var
Stream: TFileStream; begin
Stream := TFileStream.Create(FileName, fmOpenRead or
fmShareDenyWrite); try
LoadFromStream(Stream) finally
Stream.Free end
end
; procedure
TSharedStream.LoadFromStream(Stream: TStream); var
Count: Longint; begin
Stream.Position := 0; Count := Stream.Size; SetSize(Count); if
Count > 0 then
Stream.Read
(FMemory^, Count); end
; procedure
TSharedStream.SaveToFile(const
FileName: string
); var
Stream: TFileStream; begin
Stream := TFileStream.Create(FileName, fmCreate); try
SaveToStream(Stream) finally
Stream.Free end
end
; procedure
TSharedStream.SaveToStream(Stream: TStream); begin
Stream.Write(FMemory^, FSize); end
; end
.