8

0オフセットからではなく、ユーザー定義のオフセットからファイルを処理できるように、TFileStreamを拡張する必要があります。つまり、ユーザー定義のオフセットをストリームの開始として解釈する必要があります。私のコードは次のとおりです。


type
  TSuFileStream = class(TFileStream)
  protected
    FOffset : int64;

    procedure SetOffset(Offset : int64);

    procedure SetSize(NewSize: Longint); override;
    procedure SetSize(const NewSize: Int64); override;
  public
    constructor Create(const AFileName: string; Mode: Word); overload;
    constructor Create(const AFileName: string; Mode: Word; Rights: Cardinal); overload;

    function Seek(Offset: Longint; Origin: Word): Longint; override;
    function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override;

    property Offset : int64 read FOffset write SetOffset;
  end;
...
constructor TSuFileStream.Create(const AFileName: string; Mode: Word);
begin
  inherited Create(AFileName, Mode);
  FOffset := 0;
end;

constructor TSuFileStream.Create(const AFileName: string; Mode: Word; Rights: Cardinal);
begin
  inherited Create(AFileName, Mode, Rights);
  FOffset := 0;
end;

procedure TSuFileStream.SetOffset(Offset : int64);
begin
  FOffset := Offset;
  inherited Seek(FOffset, soBeginning);
end;

procedure TSuFileStream.SetSize(NewSize: Longint);
begin
  inherited SetSize(FOffset + NewSize);
end;

procedure TSuFileStream.SetSize(const NewSize: Int64);
begin
  inherited SetSize(FOffset + NewSize);
end;

function TSuFileStream.Seek(Offset: Longint; Origin: Word): Longint;
begin
  Result := Seek(Int64(Offset), TSeekOrigin(Origin));
end;

function TSuFileStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64;
begin
  case Origin of
    soBeginning: Result := inherited Seek(FOffset + Offset, soBeginning) - FOffset;
    soCurrent: Result := inherited Seek(Offset, soCurrent) - FOffset;
    soEnd: Result := inherited Seek(Offset, soEnd) - FOffset;
  end;
end;
 

しかし、それは適切に機能しません。問題はシーク機能にありますが、理由はわかりません。そのようなストリームをサードパーティコンポーネントに渡すと、TSuFileStream.Offset:=0の場合にのみ機能します。

4

2 に答える 2

8

まず、メソッドバージョンの1つのみをオーバーライドします。クラスインターフェイスからわかるように、同じメソッドのlongintバージョンとint64バージョンの両方があります(setSizeやseekなど)。これはDelphiのドキュメントにあります。int64バージョンをオーバーライドします。

次に、TFilestreamをオーバーライドするのではなく、TStreamを直接オーバーライドして、操作する「ストリーム間」を作成します。

コンストラクターには、2つのパラメーターを入れます。

  1. 任意のタイプの実際のソースストリーム
  2. オフセット

つまり、基本的に作成したいのは、実際のストリームとカスタムバージョンの間のプロキシです。このように、シークの実装では、オフセットを追加する必要があります(TMemoryStreamとTFileStreamを見て、それがどのように行われるかを確認してください)。また、あらゆるタイプのストリームソースをサポートできるという利点もあります。

使いやすいプロキシを作成する必要があります。

mMyStream:=TMyProxyStream.Create(mRealStream,2800); //Root offset at 2800
try
  mMyStream.Read(mBuffer,1024); // After read, offset = 3824
  mMyStream.position:=0; //Reset offset back to to 2800
finally
  mMyStream.free;
end;

シーク機能の計算は少し難しい場合があります。これは、バッファシステム用にコーディングしたプロキシクラスの例です(FOffsetは内部変数であり、これは操作したいものです)。

function TSLBufferStreamAdapter.Seek(const Offset:Int64;
         Origin:TSeekOrigin):Int64;
Begin
  Case Origin of
  soBeginning:
    Begin
      if Offset>=0 then
      FOffset:=Math.EnsureRange(Offset,0,FBufObj.Size);
    end;
  soCurrent:
    Begin
      FOffset:=math.EnsureRange(FOffset + Offset,0,FBufObj.Size);
    end;
  soEnd:
    Begin
      If Offset>0 then
      FOffset:=FBufObj.Size-1 else
      FOffset:=math.EnsureRange(FOffset-(abs(Offset)),0,FBufObj.Size);
    end;
  end;
  result:=FOffset;
end;

この返信を今すぐ更新して、更新リンクを含めます。私のライブラリのバイトレイジはグーグルコードに移動しました-そこで見てください。それが役に立てば幸い!

于 2011-05-12T15:49:24.593 に答える
2

私のウェブGoogleCodeで入手できるTGpStreamWindowを使用してください

使用法:

var
  offsetStream: TGpStreamWindow;

begin
  offsetStream := TGpStreamWindow.Create(originalStream, initialOffset, originalStream.Size - 1);
  try
    DoSomethingWith(offsetStream);
    offsetStream.SetWindow(anotherInitialOffset, originalStream.Size - 1);
    DoSomethingElseWith(offsetStream);
  finally FreeAndNil(offsetStream); end;
end;
于 2011-05-13T07:15:02.380 に答える