Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ООП / ООП_Лекции.doc
Скачиваний:
50
Добавлен:
08.06.2015
Размер:
1.03 Mб
Скачать

Потоки памяти

В примере MemoStr показано, как можно копировать файл, используя объект TFileStream. Чтобы это сделать, нет необходимости создавать буфер в оперативной памяти, так как классы TFileStream делают это автоматически.

Однако бывают случаи, когда следует явно создать область памяти так, чтобы выполнить действия над данными без ограничения скорости доступа к файлу. В этом случае создается объект TMemoryStream, работающий точно так же, как любой другой поток (со свойствами размера и позиции), но использующий память вместо данных из файла на диске.

Очевидно, что вам, прежде всего, придется импортировать данные в область памяти. Чтобы сделать это, класс TMemoryStream определяет специальные методы обмена содержимого памяти с другими потоками, которыми могут быть TFileStream, THandleStream или другой объект потока. Объекты TMemoryStream особенно полезны, когда необходимо создать временный поток или моделировать временный файл в памяти.

В дополнение к свойствам size и Position, наследуемым из класса TStream, класс TMemoryStream наследует свойство Memory из класса TCustomMemoryStream. Это свойство просто возвращает указатель на блок памяти, которым манипулирует объект TMemoryStream. Как только получен этот указатель, сразу же можно выполнить необходимые действия; но их нельзя делать непосредственно, потому что данное свойство предназначено только для чтения. Чтобы связать объект с другим блоком памяти (возможно уже содержащим данные), не­обходимо использовать метод SetPointer.

Пример программыMemoryS

Исследуем, например, программу MemoryS. В этой программе задаются две кнопки: одна — для загрузки данных из файла в TMemoryStream, а другая — для отображения этих данных с использованием свойства Memory, упомянутого выше. Изображение на рис. 3.2 показывает основную форму примера MemoryS.

unit MsFormR;

interface

Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdDtls, ExtDrls;

type

Т Form1 =class(TForm) OpenDialogl: TOpenDialog;

Сначала обратите внимание, что поток памяти объявлен, как внутреннее поле формы типа private. Это сделано для того, чтобы использовать тот же объект TMemoryStream для вызова функции или процедуры. Одно из этих обращений — процедура ShowMemStr, используемая для отображения содержимого потока памяти через свойство Memory.

private

MemStrl: TMemoryStream;

procedure ShowMemStr;

Как и следовало ожидать, поток памяти создается в обработчике события формы OnCreate.

procedure TForml.FormCreate(Sender: TObject);

begin

MemStrl:= TMemoryStream.Create;

end;

Точно так же он удаляется в обработчике события формы OnDestroy:

procedure TForml.FormDestroy(Sender: TObject);

begin

MemStrl.Free;

end;

Когда пользователь нажимает кнопку «Load File», данные загружаются в TMemoryStream с использованием TFileStream:

procedure TForml.ButtonlClick(Sender: TObject);

var

Strl: TFileStream;

begin

OpenDialogl.Filter:='Any file (*.*)!*.*';

OpenDialogl.DefaultExt:= '*'; '

if OpenDialogl.Execute then

begin

Strl := TFileStream.Create(OpenDialogl.FileName, fmOpenRead);

try

MemStrl.LoadFromStream(Strl);

ShowMemStr;

Button2.Enabled := true;

finally

Strl.Free;

end;

end;

end;

Единственный новый код, добавленный здесь — это обращение к методу LoadFromStream, который просто копирует данные из потока файла в поток памяти. Так как класс TMemoryStream предоставляет метод LoadFromFile, его можно использовать следующим образом.

procedure TForml.ButtonlClick(Sender: TObject);

begin

OpenDialogl.Filter:='Any file (*.*)!*.*';

OpenDialogl.DefaultExt :='*';

if OpenDialogl.Execute then begin

MemStrl.LoadFromFile(OpenDialogl.FileName);

ShowMemStr;

end;

end;

Затем данные просто копируются из потока памяти в компонент Memo, используя метод LoadFromStream класса ТМето.

Поток памяти в Memo копируется прямолинейно:

procedure TForml.ShowMemStr;

begin

Memol.Lines.LoadFromStream(MemStrl);

end;

Очевидно, что можно просто загрузить файл непосредственно в компонент Memo, заменив обработчик события загрузки файла Load File на следующий код:

procedure TForml.ButtonlClick(Sender: TObject);

begin

OpenDialogl. Filter : = 'Any file (*,*)!*.*'•;

OpenDialogl.DefaultExt:= ' * ' ;

if OpenDialogl.Execute then

begin

Memol.Lines.LoadFromFile(OpenDialogl.FileName);

end;

end;

Однако этот подход не инициализировал бы поток памяти данными, как будет сделано в следующем примере.

В заключение добавим кнопку «Show Data». Когда пользователь нажмет эту кнопку, выполнится довольно сложный код для отображения данных в потоке памяти через свойство Memory. В первой версии примера (отсутствует на компакт-диске) использовался следующий код:

procedure TForml.Button2Click(Sender: Tobject);

var

pch: PChar;

begin

pch := MemStrl.Memory;

while (pch <> nil) and (MessageDlg('Character is ' + pch^ + #13#13 + 'Do you want to see the following one?', mtConfirmation, [mbYes, mbNo], 0) = mrYes) do

Inc(pch);

end;

Эта функция начинается инициализацией указателя типа Char с именем pch, чтобы адресовать размещение памяти в начале потока памяти. Затем записан цикл while, проверяющий сначала, имеет ли указатель pch значение nil, а затем отображающий окно диалога и проверяющий ответ пользователя. При отображении окна диалога формируется строка, содержащая символ, адресуемый указателем типа Char, простым изменением указателя (pch^). Если пользователь выбирает кнопку «Yes» в этом диалоговом окне, мы увеличиваем указатель, используя Inc(pch).

Для анализа каждого последовательного символа просто увеличивается указатель. Обратите внимание, что процедура Inc использована вместо оператора:

pch := pch + 1;

Хотя Object Pascal поддерживает арифметические операции над указателями для некоторых типов данных (типа PChar), это сделано потому, что они не поддерживаются как общая возможность языка. Объявление

var

pch: ^Char;

сделало бы невозможным применение стандартных арифметических действий над указателем.

Напротив, процедура Inc управляет указателями, основанными на размере адресуемых данных. Так как тип указателя определяет, что он адресует отдельные байты (символы), вызов Inc с этим типом указателя просто переместит указатель для адресации следующего байта.

Соседние файлы в папке ООП