How can I go down with TFileStream and TMemoryStream?

I have a class that inherits from TFileStream and a class that inherits from TMemoryStream. Both implement exactly the same functions as when reading data, for example:

TCustomFileStream = class (TFileStream)
  function ReadByte: byte;
  function ReadWord: word;
  function ReadWordBE: word;
  function ReadDWord: longword;
  function ReadDWordBE: longword;
  function ReadString(Length: integer): string;
  function ReadBlockName: string;
  etc

When I want to write a function that can accept any type of stream as a parameter, I have to use TStream:

function DoStuff(SourceStream: TStream);

This, of course, means that I cannot use my custom functions. What is the best way to handle this? Ideally, I would like to have a Tstream compatible class that works with either FileStream or MemoryStream, so I can do something like this and it doesn't matter if the stream is a file stream or a MemoryStream file:

function DoStuff(SourceStream: TMyCustomStream);
begin
    data := SourceStream.ReadDWord;
    otherData := SourceStream.Read(Buffer, 20);

end;
+4
source share
5 answers

: .:)

, :

, TFileStream , TMemoryStream.

, , .:)

I have some structured data that I need to read from different sources (different stream classes).

- . , / . , "" . , , TFileStream TMemoryStream, , . TStream TStream , , .

- , / (, , ..), - .

, , , .

(?) , . , "".

TStuffReader = class
private
  fStream: TStream;
public
  constructor Create(aStream: TStream);
  function ReadByte: byte;
  function ReadWord: word;
  function ReadWordBE: word;
  function ReadDWord: longword;
  function ReadDWordBE: longword;
  function ReadString(Length: integer): string;
  function ReadBlockName: string;
end;

( TStuffFiler, , ), TStuffWriter ().

, (/ ) / TStream. , .

.., . , , , . , , .

, - (, TBLOBStream, ), TStuffReader ( ), .

" ", . .

VCL , , , VCL - , .

not , , .

, , . .

, , , , , , .

I ( ). , , , .

, , , , , , , , - , .

Delphi , VCL.

() VCL , , . VCL, .

, VCL , .

+6

: Delphi .

, ? .

, TStream, :

TCustomStreamHelper = class helper for TStream
  function ReadByte: byte;
  function ReadWord: word;
  function ReadWordBE: word;
  function ReadDWord: longword;
  function ReadDWordBE: longword;
  function ReadString(Length: integer): string;
  function ReadBlockName: string;
  // etc.
end;

, , TCustomStreamHelper ( uses), TStream, .

+6

, () . , . TBinaryReader Classes .

+4

Delphi , .

, , TStream, , TFileStream TMemoryStream. - :

class TMyStream = class(TStream)
    private
        InternalStream: TStream;
    public
        constructor Create(InternalStream:TStream);

        /// implement all TStream abstract read, write, and seek methods and call InternalStream methods inside them.

        /// implement your custom methods here
end;

constructor TMyStream.Create(InternalStream:TStream)
begin
    Self.InternalStream=InternalStream;
end;

, , ; .

TFileStream TMemoryStream, - :

class TMyFileStream : TMyStream
public
    constructor Create(const Path:String); reintroduce;
end

constructor TMyFileStream.Create(const Path:String);
begin
    inherited Create(TFileStream.Create(Path));
end;

These workarounds are just some of the ideas that will help you get closer to what you want. Change them to suit your needs.

0
source

You can put your general methods in interfaceand implement methods QueryInterface, _AddRefand _Releasein each descendant class.

See Delphi Interfaces without reference counting .

type

  IStreamInterface = interface
    function ReadByte: byte;
    function ReadWord: word;
    function ReadWordBE: word;
    function ReadDWord: longword;
    function ReadDWordBE: longword;
    function ReadString(Length: integer): string;
    function ReadBlockName: string;
  end;

  TCustomFileStream = class (TFileStream, IStreamInterface)
    function ReadByte: byte;
    function ReadWord: word;
    function ReadWordBE: word;
    function ReadDWord: longword;
    function ReadDWordBE: longword;
    function ReadString(Length: integer): string;
    function ReadBlockName: string;

    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;

  end;

  TCustomMemoryStream = class (TMemoryStream, IStreamInterface)
    function ReadByte: byte;
    function ReadWord: word;
    function ReadWordBE: word;
    function ReadDWord: longword;
    function ReadDWordBE: longword;
    function ReadString(Length: integer): string;
    function ReadBlockName: string;

    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;

  end;

... and use the type argument IStreamInterfacefor the procedure:

procedure DoStuff(SourceStream: IStreamInterface);
var
  data: Word;
begin
  data := SourceStream.ReadDWord;
end;
0
source

Source: https://habr.com/ru/post/1653006/


All Articles