Разработка собственного поточного класса
Автор: Marco Cantu (Марко Кэнту), из книги Mastering Delphi 6 (Delphi 6 для профессионалов)

Помимо существующих поточных классов среда Delphi позволяет программистам разрабатывать собственные поточные классы и затем использовать их вместо существующих. Чтобы разработать собственный поточный класс, необходимо просто указать, каким образом должно осуществляться чтение и запись некоторого блока данных. После этого VCL сможет использовать новый класс в любом месте, где требуется использовать поток. Для того чтобы научить библиотеку VCL работать с новым типом среды хранения данных, вовсе необязательно разрабатывать совершенно новый поточный класс. Возможно будет достаточно приспособить для этой цели один из существующих потоков. В этом случае все, что вам необходимо сделать, — написать подходящие методы чтения и записи.
В качестве примера приведу разработанный мною класс кодирования и декодирования универсального файлового потока. Я не стал прилагать особенных усилий для разработки какого-то сложного кодирующего механизма, ведь данный пример разработан мною с основной целью: продемонстрировать внутреннее строение потокового класса. С этой точки зрения все замечательно: разработанный поточный класс полностью интегрирован с VCL и работает корректно. Новый потоковый класс содержит в себе два основных метода для чтения и для записи, а также включает в себя свойство, в котором хранится кодирующий ключ.

type
TEncodedStream = class (TFileStream)
private
FKey: Char;
public
constructor Create(const FileName: string; Mode: Word);
function Read(var Buffer; Count: Longint): Longint; override;
function Write(const Buffer; Count: Longint): Longint; override;
property Key: Char read FKey write FKey;
end;

Значение ключа просто добавляется к каждому записываемому в файл байту. В процессе чтения происходит декодирование: значение ключа вычитается из читаемых байтов. Приведу полный код методов Read и Write, в которых интенсивно используются указатели.

constructor TEncodedStream.Create(const FileName: string; Mode: Word);
begin
inherited
Create (FileName, Mode);
FKey := 'A'; // по умолчанию
end;
function
TEncodedStream.Write(const Buffer; Count: Longint): Longint;
var
pBuf, pEnc: PChar;
I, EncVal: Integer;
begin
// выделение памяти для закодированного буфера
GetMem (pEnc, Count);
try
// буфер используется в виде массива символов
pBuf := PChar (@Buffer);
// для каждого символа в буфере
for I := 0 to Count - 1 do
begin
// закодировать значение и сохранить его
EncVal := ( Ord (pBuf[I]) + Ord(Key) ) mod 256;
pEnc [I] := Chr (EncVal);
end;
// записать закодированный буфер в файл
Result := inherited Write (pEnc^, Count);
finally
FreeMem (pEnc, Count);
end;
end;
function
TEncodedStream.Read(var Buffer; Count: Longint): Longint;
var
pBuf, pEnc: PChar;
I, CountRead, EncVal: Integer;
begin
// выделение памяти для закодированного буфера
GetMem (pEnc, Count);
try
// чтение закодированного буфера из файла
CountRead := inherited Read (pEnc^, Count);
// использовать буфер вывода в качестве строки
pBuf := PChar (@Buffer);
// для каждого реально прочитанного символа
for I := 0 to CountRead - 1 do
begin

// декодировать значение и сохранить его
EncVal := ( Ord (pEnc[I]) - Ord(Key) ) mod 256;
pBuf [I] := Chr (EncVal);
end;
finally
FreeMem (pEnc, Count);
end;
// вернуть количество прочитанных символов
Result := CountRead;
end;

Комментарии помогут вам разобраться в этом достаточно сложном коде. Теперь, когда у нас есть кодирующий поток, мы можем использовать его в демонстрационной программе под названием EncDemo. На форме этой программы располагается два компонента Memo и три кнопки. При щелчке на первой кнопке в первый компонент Memo загружается обычный текстовый файл. Вторая кнопка записывает текст, содержащийся в первом компоненте Memo, в файл в закодированном виде. Наконец, последняя кнопка загружает содержимое этого файла во второй компонент Memo в декодированном виде. В данном примере я попытался загрузить содержимое закодированного файла в первый компонент Memo в виде обычного текста, и конечно же, отображаемый в этом компоненте текст невозможно прочитать.

Используются технологии uCoz