TFileStream со смещением - PullRequest
8 голосов
/ 12 мая 2011

Мне нужно расширить TFileStream, чтобы он мог работать с файлом не с 0 смещением, а с заданным пользователем смещением. Я имею в виду, что он должен интерпретировать заданное пользователем смещение как начало потока. Мой код:


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;

Ответы [ 2 ]

8 голосов
/ 12 мая 2011

Во-первых, переопределите только одну из версий метода. Как видно из интерфейса класса, у вас есть и 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;

Я обновляю этот ответ сейчас, чтобы включить ссылку на обновление. Моя библиотека byterage перешла на Google Code - посмотрите там. Надеюсь, это поможет!

2 голосов
/ 13 мая 2011

Использование TGpStreamWindow , доступно на моем вебе и на Google Code .

Использование:

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;
...