#delphi #stream #tfilestream #tstream
#delphi #поток #tfilestream #tstream
Вопрос:
Мне нужно расширить 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.Смещение:= 0;
Ответ №1:
Сначала переопределите только одну из версий метода. Как вы можете видеть из интерфейса класса, у вас есть как longint, так и int64 версии одних и тех же методов (например, setSize и seek). Это в документации Delphi. Переопределите версии int64.
Во-вторых, я бы не переопределял TFileStream, а скорее TStream напрямую, чтобы создать «промежуточный поток» для работы.
В конструкторе я бы поместил 2 параметра:
- Фактический исходный поток любого типа
- Смещение
Итак, по сути, вы хотите создать прокси-сервер между реальным потоком и вашей пользовательской версией. Таким образом, в вашей реализации seek все, что вам нужно, это добавить смещение (посмотрите на 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:
Используйте 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;