TSharedStream — класс упрощающий работу с файлом подкачки

Советы » Файлы » TSharedStream — класс упрощающий работу с файлом подкачки

unit

SharedStream; interface

uses

SysUtils, Windows, Classes, Consts; type

{ TSharedStream } TSharedStream = class

(TStream) { Для совместимости с TStream } private

FMemory : Pointer; { Указатель на данные } FSize : Longint; { Реальный размер записанных данных } FPageSize : Longint; { Размер выделенной "страницы" под данные } FPosition : Longint; { Текущая позиция "курсора" на "странице" } protected

public

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 файла подкачки } implementation

resourcestring

CouldNotMapViewOfFile = 'Could not map view of file.'; { TSharedStream } { * TSharedStream работает правильно только с файлом подкачки, с обычным файлом проще и надежнее работать TFileStream'ом. * Для тех кто знаком с File Mapping Functions'ами : Класс TSharedStream не может использоваться для синхронизации(разделения) данных среди различных процессов(программ/приложений). [пояснения в конструкторе] * Класс TSharedStream можно рассматривать как альтернативу временным файлам (т.е. как замену TFileStream). Преимущество : а. Данные никто не сможет просмотреть. б. Страница, зарезервированная под данные, автомотически освобождается после уничтожения создавшего ее TSharedStream'а. * Класс TSharedStream можно рассматривать как альтернативу TMemoryStream. Преимущество : а. Не надо опасаться нехватки памяти при большом объеме записываемых данных. [случай когда физически нехватает места на диске здесь не рассматривается]. Известные проблемы: На данный момент таких не выявлено. Но есть одно НО. Я не знаю как поведет себя TSharedStream в результате нехватки места а. на диске б. в файле подкачки (т.е. в системе с ограниченным размером файла подкачки). } constructor

TSharedStream.Create; const

Sz = 1024000; { Первоначальный размер страницы }{ взят с потолка } var

SHandle : 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'ами : раз страница осталась неименованной, то Вам не удастся использовать ее для синхронизации(разделения) данных среди различных процессов(программ/приложений). [остальных недолжно волновать это отступление] } if

SHandle = 0 then

raise

Exception.Create(CouldNotMapViewOfFile); { ошибка - неудалось создать объект отображения[т.е. "страница" не создана и указатель на нее = 0]. Это может быть: Если Вы что-либо изменяли в конструкторе - a. Из-за ошибки в параметрах, передоваемых функции CreateFileMapping б. Если Sz <= 0 Если Вы ничего не изменяли - а. То такое бывает случается после исключительных ситуаций в OS или некорректной работы с FileMapping'ом в Вашей или чужой программе. Помогает перезагрузка виндуса } FMemory := MapViewOfFile(SHandle, FILE_MAP_WRITE, 0, 0, Sz); { Получаем указатель на данные } if

FMemory = nil

then

raise

Exception.Create(CouldNotMapViewOfFile); { Виндус наверно может взбрыкнуться и вернуть nil, но я таких ситуаций не встречал. естественно если на предыдущих дейсвиях не возникало ошибок и если переданы корректные параметры для функции MapViewOfFile() } CloseHandle(SHandle); end

; destructor

TSharedStream.Destroy; begin

UnmapViewOfFile(FMemory); { закрываем страницу. если у Вас не фиксированный размер файла подкачки, то через пару минут вы должны увидеть уменьшение его размера. } inherited

Destroy; 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; { Запоминаем размер данных } if

FPosition > 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

.

Другое по теме:

Категории

Статьи

Советы

Copyright © 2022 - All Rights Reserved - www.delphirus.com