Урок 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.