Sunday, September 20, 2009

Stream classes

This post is about Delphi Stream classes, if you continue reading it there's a chance you will find out new things about them.
Let's start with the base stream class which is TStream and it's defined as
  TStream = class(TObject)
  private
    function GetPosition: Int64;
    procedure SetPosition(const Pos: Int64);
    procedure SetSize64(const NewSize: Int64);
  protected
    function GetSize: Int64; virtual;
    procedure SetSize(NewSize: Longint); overload; virtual;
    procedure SetSize(const NewSize: Int64); overload; virtual;
  public
    function Read(var Buffer; Count: Longint): Longint; virtual; abstract;
    function Write(const Buffer; Count: Longint): Longint; virtual; abstract;
    function Seek(Offset: Longint; Origin: Word): Longint; overload; virtual;
    function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; overload; virtual;
    procedure ReadBuffer(var Buffer; Count: Longint);
    procedure WriteBuffer(const Buffer; Count: Longint);
    function CopyFrom(Source: TStream; Count: Int64): Int64;
    function ReadComponent(Instance: TComponent): TComponent;
    function ReadComponentRes(Instance: TComponent): TComponent;
    procedure WriteComponent(Instance: TComponent);
    procedure WriteComponentRes(const ResName: string; Instance: TComponent);
    procedure WriteDescendent(Instance, Ancestor: TComponent);
    procedure WriteDescendentRes(const ResName: string; Instance, Ancestor: TComponent);
    procedure WriteResourceHeader(const ResName: string; out FixupInfo: Integer);
    procedure FixupResourceHeader(FixupInfo: Integer);
    procedure ReadResHeader;
    property Position: Int64 read GetPosition write SetPosition;
    property Size: Int64 read GetSize write SetSize64;
  end;

as you can see TStream's definition it is a abstract class, any class derived from TStream can be passed as parameter in a function call like
procedure DoSomething(Stream: TStream);
 ...

you can pass a TMemoryStream, TFileStream or any class variable which is derived from it.
Any class which is derived from TStream must override the abstract procedures and functions.

TFileStream class is derived from THandleStream(which is derived from TStream), it's defined as
{ THandleStream abstract class }

  THandleStream = class(TStream)
  protected
    FHandle: Integer;
    procedure SetSize(NewSize: Longint); override;
    procedure SetSize(const NewSize: Int64); override;
  public
    constructor Create(AHandle: Integer);
    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;
    property Handle: Integer read FHandle;
  end;

{ TFileStream class }

  TFileStream = class(THandleStream)
  public
    constructor Create(const FileName: string; Mode: Word); overload;
    constructor Create(const FileName: string; Mode: Word; Rights: Cardinal); overload;
    destructor Destroy; override;
  end;

Note: Any class derived from TStream class or a class which is derived from TStream must override the Read, Write, Seek and SetSize methods so it can manipulate data and/or implement new methods/properties.
An example on TFileStream usage can be found at this post.

TMemoryStream class is useful for writing blocks of data in memory so you have faster access to it then you would if you where using a TFileStream.

A TStringStream class usage example can be found on this post.

TResourceStream description(Delphi 7 help)
Use TResourceStream to read the resources of an application. An instance of TResourceStream holds the value of a single resource in a memory buffer where it is accessible to the application.
The global ReadComponentRes function uses TResourceStream to access the compiled resources used by the application.

TWinSocketStream description(Delphi 7 Help)
Use TWinSocketStream to read or write information over a blocking socket connection. Windows socket objects include methods to read from or write to the socket connection they represent. However, these methods do not provide a mechanism for timing out when the socket connection is dropped or for waiting until the socket connection is ready before reading.

When the socket is a non-blocking socket, this lack of a time-out or waiting mechanism is not a problem, because reading and writing occur asynchronously in response to notifications from the socket connection. For blocking sockets, however, these mechanisms provided by TWinSocketStream are necessary so that the application using the socket does not hang indefinitely.
To use a Windows socket stream, create an instance of TWinSocketStream, use the methods of the stream to read or write the data, and then free the Windows socket stream.
Note: TWinSocketStream does not work with non-blocking sockets.
An alternative to TWinSocketStream is Primoz Gabrijelcic's TSafeWinSocketStream class that can be downloaded from this link.

Example of using TWinSocketStream
procedure TheClientThread.Execute;
var
  TheStream: TWinSocketStream;
  Buffer: string;
begin
  (* create a TWinSocketStream for reading and writing *)
  TheStream := TWinSocketStream.Create(ClientSocket1.Socket, 60000);
  try
    (* fetch and process commands until the connection or thread is terminated *)
    while (not Terminated) and (ClientSocket1.Active) do begin
      try
        (* GetNextRequest must be a thread-safe method *)
        GetNextRequest(Buffer);
        (* write the request to the server *)
        TheStream.Write(Buffer, Length(Buffer) + 1);
        (* continue the communication (eg read a response from the server) *)
        (* ... *)
      except
        if not(ExceptObject is EAbort) then
          (* you must write HandleThreadException *)
          Synchronize(HandleThreadException);
      end;
    end;
  finally
   TheStream.free;
  end;
end;

No comments:

Post a Comment

Blogroll(General programming and Delphi feeds)