Урок 79 - Использование потоков данных (часть 3/3)

Звучит это все страшно, а используется очень просто. Вот пример.

var
  strm : IStream; 
  mem : TMemorySteam;
Begin
  mem := TMemorySteam.Create;
  strm := TStreamAdapter.Create(mem, soOwned) as IStream;
Все теперь передаем интерфейс strm в Dll ил вообще куда угодно и не думаем о уничтожении ни TStreamAdapter ни TMemorySteam, в нужное время они сами уничтожаться, тогда когда клиент закончит с ними работать.

Теперь рассмотрим случай, когда программа на делфи является не сервером, а клиентов, т.е. ей передают интерфейс IStream, объекта потока созданного неизвестно где. Идеально было бы если бы мы получили не IStream, а TStream, ведь все объекты VCL умеют работать именно с TStream, а работать с IStream они не умеют. Решение в лоб состоит в том, чтобы банально скопировать все данные из IStream например в TMemorySteam. Однако, таким образом мы получаем лишнее копирование. Это ничего, когда данных на 20кб, другое дело если их 1Гб, тогда дополнительное копирование выйдет боком. Для таких случаев предлагаю написать свой собственный адаптер, но уже не адаптер сервера, а клиента. Класс назвал TExternStream (от слова External т.е. внешний). Заодно это будет пример написания своего класса наследника TStream. Основная задача этого класса переадресовать все запросы интерфейсу внешнего объекта IStream. Сам интерфейс нужно передать в конструктор. В деструкторе интерфейс освобождается FSource := nil; в классе перекрыты все абстрактные методы Read, Write, виртуальный Seek, GetSize и SetSize.
type
  TExternStream = class(TStream)
  protected
    FSource : IStream;
    procedure SetSize(const NewSize: Int64); override;
  public
    constructor Create(Source : IStream);
    destructor Destroy; override;
    function Read(var Buffer; Count: Longint): Longint; override;
    function Write(const Buffer; Count: Longint): Longint; override;
    function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override;
  end;
procedure TForm1.FormCreate(Sender: TObject);
var
  T : TStreamAdapter;
begin
  RegisterComponents
end;
{ TExternStream }
constructor TExternStream.Create(Source: IStream);
begin
  inherited Create;
  FSource := Source;
end;
destructor TExternStream.Destroy;
begin
  FSource := nil;
  inherited;
end;
function TExternStream.Read(var Buffer; Count: Integer): Longint;
begin
  if FSource.Read(@Buffer, Count, @Result) <> S_OK
  then
    Result := 0;
end;
function TExternStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64;
begin
  FSource.Seek(Offset, byte(Origin), Result);
end;
procedure TExternStream.SetSize(const NewSize: Int64);
begin
  FSource.SetSize(NewSize);
end;
function TExternStream.Write(const Buffer; Count: Integer): Longint;
begin
  if FSource.Write(@Buffer, Count, @Result) <> S_OK
  then
    Result := 0;
end;
Используется все это счастье следующим образм. Пусть в клиенсткую часть передали интерфейс strm : IStream, тогда создаем свой экземпляр класса TExternStream на базе этого strm и используем как любой другой объект наследник TStream. Напрмер вызываем Image1.Picture.Bitmap.LoadFromStream(aOut);
var
  aOut : TExternStream;
try
  aOut := TExternStream.Create(strm);
  Image1.Picture.Bitmap.LoadFromStream(aOut);
....
  aOut.Free; //Тут уничтожиться поток созданный в Dll, так как указатель на aStream занулиться. 
  


Удачи!
Встретимся в следующем уроке!




Добавил(а): v1dark Дата: 2013-11-20
Админ Написал бы многопоточний "бурт" и показал как изпользвоать потоки и обяснить там много чего есть.урок будет во


    No results found.
Отменить.