Rambler's Top100
"Knowledge itself is power"
F.Bacon
Поиск | Карта сайта | Помощь | О проекте | ТТХ  
 Сокровищница
  
 

Фильтр по датам

 
 К н и г и
 
Книжная полка
 
 
Библиотека
 
  
  
 


Поиск
 
Поиск по КС
Поиск в статьях
Яndex© + Google©
Поиск книг

 
  
Тематический каталог
Все манускрипты

 
  
Карта VCL
ОШИБКИ
Сообщения системы

 
Форумы
 
Круглый стол
Новые вопросы

 
  
Базарная площадь
Городская площадь

 
   
С Л С

 
Летопись
 
Королевские Хроники
Рыцарский Зал
Глас народа!

 
  
ТТХ
Конкурсы
Королевская клюква

 
Разделы
 
Hello, World!
Лицей

Квинтана

 
  
Сокровищница
Подземелье Магов
Подводные камни
Свитки

 
  
Школа ОБЕРОНА

 
  
Арсенальная башня
Фолианты
Полигон

 
  
Книга Песка
Дальние земли

 
  
АРХИВЫ

 
 

Сейчас на сайте присутствуют:
 
  
 
Во Флориде и в Королевстве сейчас  21:42[Войти] | [Зарегистрироваться]

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

Алексей Румянцев
дата публикации 05-09-2001 12:06

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

TSharedStream (версия 1).

Когда-то (кажется год назад) на страницах "королевства" я прочитал статью об использовании файла подкачки как о временном хранилище данных. ( Имеется ввиду статья Дмитрия Логинова Ядро системы и антиотладочные приемы.) После этой статьи я заинтересовался работой с Swap'ом.
Некотое время в работе я пользовался чисто FileMappingFun'кциями, что оказалось нудно и трудоемко (не так чтобы очень, но согласитесь, что легче хранить всю информацию в одном месте[классе], чем иметь несколько переменных и помнить когда и как их надо использовать).
Написал первую версию класса-обертки над FileMappingFun'кциями и все как-будто было нормально, но убивало одно НО - не было возможности изменять размер области["страницы"] под данные выделенной при ее создании, т.е. надо было заранее знать размер информации, которую вы собираетесь в нее записать. В TSharedStream я решил эту проблему, плохо или хорошо трудно сказать - по сравнению с невозможностью изменить размер - хорошо, а по качеству реализации - не очень.

Прошло н-ное кол-во времени, появилось желание сделать работу класса правильней, действенней, качественней (нужного слова не подобрать).

TRySharedStream(версия 2)

TRySharedStream(версия 2) - полностью переписанная версия TSharedStream.
Пользовательская сторона работы с классом осталась неизменной (единственное был переименован сам класс и его юнит), а внутреннее содержание претерпело изменения. Не бойтесь, работа файла подкачки не изменилась :o), а вот работа TSharedStream меня устраивать перестала - пересоздание бОльших по объему страниц и перемещение данных из одной в другую по несколько раз хоть и работает быстро, но выглядело по скобарски.

Для решения этой проблемы рассматривались альтернативные варианты, которые особо не улудшали ситуацию, так например вариант с созданием одной, но большой страницы проблему лишь временно скрывало, но не решало ее.
Результатом же раздумий стал многостраничный вариант, т.е. группа маленьких страниц, хранящих информацию, при необходимости добавляются новыми страницами в которые и дозаписываются данные, в результате
  • а. страница в файле подкачки становится как бы резиновой.
  • б. винт не занимается бессмысленной работой.
  • в. место на диске (в Swap'е) расходуется экономично(экономично или нет, будет зависеть уже только от вас - сколько вы туда запишете :o))
  • г. скорость (скорость вас должна порадовать и поэтому этот пункт можно назвать не "г" а "с" - от слова "свист", т.е. работать будет со свистом.
Хотя и здесь есть двусмыслица: с одной стороны если программа работает со свистом, то это хорошо, а если винт работает с подозрительным свистом, то это плохо. :o)).

Результатом так же стало разделением TSharedStream на два класса TRySharedMem и TRySharedStream.
TRySharedMem -
  • сам по себе независимый класс, потомок TObject, не тянущий за собой Forms, TApplication, TComponent и т.п.;
  • является чисто оберткой над FileMappingFunctions, но скрывающий все сложности обращения с ними;
  • позволяет создавать объект файлового отображения (как страничного swap-файла, так и обычного файла);
  • позволяет разделять одну область отображения между различными процессами(программами);
  • имеет дополнительные функции Read/Write (аналогичные TStream.Read/TStream.Write).
TRySharedStream - Потомок TStream, не тянущий за собой Forms, TApplication, TComponent и т.п. базируется на работе TRySharedMem, аналог временным файлам и постоянным страхам нехватки памяти - т.е. аналог TFileStream и TMemoryStream; расширяет возможности работы с файлом подкачки - размер записываемых данных ограничивается толь местом на диске.

Единственное сейчас TRySharedStream не поддерживает разделения области отображения между различными процессами(программами) как в TRySharedMem, но в следующей версии, скорей всего, эта возможность будет доступна (мысль как это сделать уже есть).

 

Лицензионное соглашение.

Лицензионное соглашение написано в каждом сооветствующем юните, здесь же написано некоторое пояснение :
TRySharedMem и TRySharedStream - это, по большому счету, базируются на результате(ах) работы FileMappingFunctions, но немалое значение здесь имеет и человеческий фактор: как вы распорядитесь объектами отображения, какой файл вы отобразите и что, как и сколько вы туда запишите никто не может знать, а файловая область, как вы знаете, это не шутка. Поэтому программный код дается вам бесплатно, по принципу "as is". Автор и "Королевство Дельфи" снимают с себя всю ответственность за результаты работы классов. Весь риск по работе с этими классами ложится на вас и только вас. Если вы не согласны с лицензионным соглашением или с некоторыми пунктами - вы не должны использовать данный програмный код в ваших проектах.

Класс TRySharedSream.

unit RySharedStream; 
 
interface 
 
uses 
  SysUtils, Windows, Classes, RySharedMem; 
 
{$IFDEF VER120} 
  {$DEFINE D5} 
{$ENDIF} 
{$IFDEF VER130} 
  {$DEFINE D5} 
{$ENDIF} 
{$IFDEF VER140} 
  {$DEFINE D6} 
{$ENDIF} 
 
type 
 
{ TRyPageList } 
 
  TRyPageList = class(TList) 
  protected 
    function  Get(Index: Integer): TRySharedMem; 
    procedure Put(Index: Integer; Item: TRySharedMem); 
  public 
    property  Items[Index: Integer]: TRySharedMem read Get write Put; default; 
  end; 
 
{ TRySharedStream } 
 
  TRySharedStream = class(TStream)  { Для совместимости с TStream } 
  private 
    FSize     : Longint;          { Реальный размер записанных данных } 
    FPosition : Longint; 
    FPages    : TRyPageList; 
  protected 
    function  NewPage: TRySharedMem; 
  public 
    constructor Create; 
    destructor  Destroy; override; 
    function  Read(var Buffer; Count: Longint): Longint; override; 
    function  Write(const Buffer; Count: Longint): 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 
  end; 
 
implementation 
 
uses RyActiveX; 
 
{resourcestring 
  CouldNotMapViewOfFile = 'Could not map view of file.';} 
 
{ TRySharedStream } 
 
{ 
  * Класс TRySharedStream можно рассматривать как альтернативу 
    временным файлам (т.е. как замену TFileStream). 
    Преимущество : 
      а. Данные никто не сможет просмотреть. 
      б. Страницы, зарезервированные под данные, автомотически освобождаются 
         после уничтожения создавшего ее TRySharedStream'а. 
 
  * Класс TRySharedStream можно рассматривать как альтернативу 
    TMemoryStream. 
    Преимущество : 
      а. Не надо опасаться нехватки памяти при большом объеме записываемых данных. 
         [случай когда физически нехватает места на диске здесь не рассматривается]. 
 
  Известные проблемы: 
    На данный момент таких не выявлено. 
    Но есть одно НО. Я не знаю как поведет себя TRySharedStream 
    в результате нехватки места 
      а. на диске 
      б. в файле подкачки (т.е. в системе с ограниченным размером 
                           файла подкачки). 
} 
const 
  PageSize = 1024000; { размер страницы } 
 
constructor TRySharedStream.Create; 
begin 
  FPosition := 0;   { Позиция "курсора" } 
  FSize     := 0;   { Размер данных } 
  FPages    := TRyPageList.Create; 
  FPages.Add(NewPage); 
end; 
 
destructor TRySharedStream.Destroy; 
begin 
  with FPages do 
    while Count > 0 do 
    begin 
      Items[Count - 1].Free; 
      Delete(Count-1); 
    end; 
  FPages.Free; 
  inherited; 
end; 
 
function TRySharedStream.NewPage: TRySharedMem; 
begin 
  Result := TRySharedMem.Create(RyActiveX.GUIDToString(RyActiveX.GetGUID), 0, PageSize) 
  {                                         |} 
  {Я знаю что можно не именовать страницу __|} 
  {но оказалось не всегда Win98 правильно создает новую} 
  {неименнованную страницу. а другого способа получения} 
  {уникальной строки я не знаю.                        } 
  {если у кого-то будут идеи по этому поводу - милости просим.} 
end; 
 
function TRySharedStream.Read(var Buffer; Count: Longint): Longint; 
var 
  FPos, BPos, FPageNo: Integer; 
  ACount, FCount : Longint; 
  Buf: PChar; 
begin 
  Buf := @Buffer; 
  ACount := 0; 
  if Count > 0 then 
  begin 
    FCount := FSize - FPosition; {максимальное кол-во, которое можно прочитать} 
    if FCount > 0 then 
    begin 
      if FCount > Count then FCount := Count; {если нам нужно прочитать меньше чем можем} 
      ACount := FCount; {запоминаем сколько надо} 
      FPageNo := FPosition div PageSize; {т.к. у нас многостраничный stream, то 
      находим с какой страницы начать читать} 
      BPos := 0; 
      FPos := FPosition - (PageSize * FPageNo); {с какой позиции на странице читаем} 
      while FCount > 0 do 
      begin 
        if FCount > (PageSize - FPos) then 
           Count := PageSize - FPos else Count := FCount; {определяем 
           сколько можно прочитать со страницы} 
        Move(PChar(FPages.Items[FPageNo].Memory)[FPos], Buf[BPos], Count); 
        {считаваем инфо. в буффер} 
        Inc(FPageNo); {переходим на следующую страницу} 
        Dec(FCount, Count); 
        Inc(BPos, Count); 
        FPos := 0; 
      end; 
      Inc(FPosition, ACount); 
    end 
  end; 
 
  Result := ACount; 
end; 
 
function TRySharedStream.Write(const Buffer; Count: Longint): Longint; 
var 
  FPos, BPos, FPageNo: Integer; 
  ASize, ACount, FCount : Longint; 
  Buf: PChar; 
begin { Функция аналогичная TStream.Write(). 
        Все пояснения по работе с ней см. в help'e. } 
  Buf := @Buffer; 
  if Count > 0 then 
  begin 
    ASize := FPosition + Count; {определяем сколько места нужно для данных} 
    if FSize < ASize then Size := ASize; {если больше чем было, то увеличиваем размер стрима} 
 
    FCount := Count; {запоминаем сколько надо записать} 
    FPageNo := FPosition div PageSize; {определяем с какой страницы начинаем писать} 
    BPos := 0; 
    FPos := FPosition - (PageSize * FPageNo); {вычисляем позицию на странице} 
    while FCount > 0 do {пока все не напишем ни куда не уходим} 
    begin 
      if FCount > (PageSize - FPos) then 
         ACount := PageSize - FPos else ACount := FCount; 
      Move(Buf[BPos], PChar(FPages.Items[FPageNo].Memory)[FPos], ACount); 
      {пишем сколько влезает до конца страницы} 
      Inc(FPageNo); {переходим на следующую страницу} 
      Dec(FCount, ACount); {уменьшаем кол-во незаписанных на кол-во записанных} 
      Inc(BPos, ACount); 
      FPos := 0; 
    end; 
    FPosition := ASize; 
  end; 
 
  Result := Count; 
end; 
 
function TRySharedStream.Seek(Offset: Longint; 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 TRySharedStream.SetSize(NewSize: Longint); 
var 
  Sz: Longint; 
begin { Функция аналогичная TStream.SetSize(). 
        Все пояснения по работе с ней см. в help'e. } 
  inherited SetSize(NewSize); 
 
  if NewSize > (PageSize * FPages.Count) then { Если размер необходимый для записи 
  данных больше размера выделенного под наш stream, то мы должны 
  увеличить размер stream'a} 
  begin { ...но FileMapping не поддерживает изменения размеров "страницы", 
    что не очень удобно, поэтому приходится выкручиваться. } 
 
    Sz := NewSize div (PageSize * FPages.Count); 
    { думаем сколько нужно досоздать страниц под данные } 
    while Sz > 0 do {создаем страницы} 
    begin 
      FPages.Add(NewPage); 
      Dec(Sz); 
    end; 
  end; 
 
  FSize := NewSize;   { Запоминаем размер данных } 
 
  if FPosition > FSize then FPosition := FSize; 
end; 
 
procedure TRySharedStream.LoadFromFile(const FileName: string); 
var 
  Stream: TFileStream; 
begin 
  Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); 
  try 
    LoadFromStream(Stream) 
  finally 
    Stream.Free 
  end 
end; 
 
procedure TRySharedStream.LoadFromStream(Stream: TStream); 
begin 
  CopyFrom(Stream, 0); 
end; 
 
procedure TRySharedStream.SaveToFile(const FileName: string); 
var 
  Stream: TFileStream; 
begin 
  Stream := TFileStream.Create(FileName, fmCreate); 
  try 
    SaveToStream(Stream) 
  finally 
    Stream.Free 
  end 
end; 
 
procedure TRySharedStream.SaveToStream(Stream: TStream); 
begin 
  Stream.CopyFrom(Self, 0); 
end; 
 
{ TRyPageList } 
 
function TRyPageList.Get(Index: Integer): TRySharedMem; 
begin 
  Result := TRySharedMem(inherited Get(Index)) 
end; 
 
procedure TRyPageList.Put(Index: Integer; Item: TRySharedMem); 
begin 
  inherited Put(Index, Item) 
end; 
 
end. 

Алексей Румянцев
Специально для Королевства Delphi

Прилагается демонстрационный пример использования TRySharedStream : SwapStream.zip(32 K)
Обновление от 17.04.03




Смотрите также материалы по темам:
[TStream] [TMemoryStream] [TFileStream] [TMemo] [Exception] [Функции для работы с файлами ] [Файл подкачки] [Маппированные файлы]

 Обсуждение материала [ 17-04-2003 14:43 ] 10 сообщений
  
Время на сайте: GMT минус 5 часов

Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter.
Функция может не работать в некоторых версиях броузеров.

Web hosting for this web site provided by DotNetPark (ASP.NET, SharePoint, MS SQL hosting)  
Software for IIS, Hyper-V, MS SQL. Tools for Windows server administrators. Server migration utilities  

 
© При использовании любых материалов «Королевства Delphi» необходимо указывать источник информации. Перепечатка авторских статей возможна только при согласии всех авторов и администрации сайта.
Все используемые на сайте торговые марки являются собственностью их производителей.

Яндекс цитирования