2011-05-12 64 views
8

我需要扩展TFileStream,以便它可以使用不是来自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; 

但它不起作用propertyly。问题在于Seek函数,但我不知道为什么。当我将这样的流传递给第三方组件时,它只有在TSuFileStream.Offset:= 0;

回答

2

使用TGpStreamWindow,可在my webGoogle 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; 
8

首先,只覆盖其中一个方法版本。正如你可以从类接口看到的,你有同样方法的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已经转移到谷歌代码 - 看看那里。希望能帮助到你!