TFileStream with offset
I need to extend TFileStream so that it can work with a file not from 0 offset, but from user defined offset. I mean it must interpret user defined offset as stream beginning. My code is:
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;
...
co开发者_运维技巧nstructor 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;
but it does not work propertly. The problem is in Seek function but I don't know why. When I pass such stream to a third party component it works only if TSuFileStream.Offset := 0;
First, only override one of the method versions. As you can see from the class interface you have both longint and int64 versions of the same methods (like setSize and seek). This is in the Delphi documentation. Override the int64 versions.
Secondly, I would not override TFilestream but rather TStream directly to create a "in between stream" to work with.
In the constructor I would put 2 parameters:
- Actual source stream of any type
- Offset
So basically what you want to create is a proxy between the real stream and your custom version. That way, in your seek implementation all you have to add the offset (look at TMemoryStream and TFileStream to see how it's done) to the position. You also get the benefit of supporting any type of stream-source.
You should end up with a proxy that is easy to use:
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;
The seek functionality can be a bit tricky to calculate. Here is an example from a proxy class i coded for my buffer system (FOffset being an internal variable, this is the one you want to manipulate):
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;
I update this reply now to include an update link. My library byterage has moved to google code - have a look there. Hope it helps!
Use TGpStreamWindow, available on my web and on Google Code.
Usage:
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;
精彩评论