unit UBufferedFS; {$IFDEF FPC} {$MODE Delphi} {$ENDIF} interface uses KOL; type PBufferedFS = PStream; { const BufferSize=$10000;//64K type TBFSMode=(BFMRead,BFMWrite); TBufferedFS=class(TFileStream) private membuffer:array [0..BufferSize-1] of byte; bytesinbuffer:integer; bufferpos:integer; bufferdirty:boolean; Mode:TBFSMode; procedure _Init; procedure Flush; procedure ReadBuffer; public constructor Create(const FileName: string; Mode: Word); overload; constructor Create(const FileName: string; Mode: Word; Rights: Cardinal); overload; destructor Destroy; override; function Read(var Buffer; Count: Longint): Longint; override; function Write(const Buffer; Count: Longint): Longint; override; function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override; end; type TByteArray = array of byte; PByteArray = ^TByteArray; } implementation { function MovePointer(const P:pointer;const dist:integer):pointer; begin result:=pointer(integer(p)+dist); end; procedure TBufferedFS.Init; begin bytesinbuffer:=0; bufferpos:=0; bufferdirty:=false; mode:=BFMWrite; end; procedure TBufferedFS.Flush; begin if bufferdirty then inherited Write(membuffer[0],bufferpos); bufferdirty:=false; bytesinbuffer:=0; bufferpos:=0; end; constructor TBufferedFS.Create(const FileName: string; Mode: Word); begin inherited; init; end; constructor TBufferedFS.Create(const FileName: string; Mode: Word; Rights: Cardinal); begin inherited; init; end; destructor TBufferedFS.Destroy; begin flush; inherited; end; procedure TBufferedFS.ReadBuffer; begin flush; bytesinbuffer:=inherited Read(membuffer,buffersize); bufferpos:=0; end; function TBufferedFS.Read(var Buffer; Count: Longint): Longint; var p:PByteArray; bytestoread:integer; b:integer; begin if Mode=BFMWrite then flush; mode:=BFMRead; result:=0; if count<=bytesinbuffer then begin //all data already in buffer move(membuffer[bufferpos],buffer,count); bytesinbuffer:=bytesinbuffer-count; bufferpos:=bufferpos+count; result:=count; end else begin bytestoread:=count; if (bytestoread<>0)and(bytesinbuffer<>0) then begin //read data remaining in buffer and increment data pointer b:=Read(buffer,bytesinbuffer); p:=PByteArray(@(TByteArray(buffer)[b])); bytestoread:=bytestoread-b; result:=b; end else p:=@buffer; if bytestoread>=BufferSize then begin //data to read is larger than the buffer, read it directly result:=result+inherited Read(p^,bytestoread); end else begin //refill buffer ReadBuffer; //recurse result:=result+Read(p^,math.Min(bytestoread,bytesinbuffer)); end; end; end; function TBufferedFS.Write(const Buffer; Count: Longint): Longint; var p:pointer; bytestowrite:integer; b:integer; begin if mode=BFMRead then begin seek(-BufferSize+bufferpos,soFromCurrent); bytesinbuffer:=0; bufferpos:=0; end; mode:=BFMWrite; result:=0; if count<=BufferSize-bytesinbuffer then begin //all data fits in buffer bufferdirty:=true; move(buffer,membuffer[bufferpos],count); bytesinbuffer:=bytesinbuffer+count; bufferpos:=bufferpos+count; result:=count; end else begin bytestowrite:=count; if (bytestowrite<>0)and(bytesinbuffer<>BufferSize)and(bytesinbuffer<>0) then begin //write data to remaining space in buffer and increment data pointer b:=Write(buffer,BufferSize-bytesinbuffer); p:=MovePointer(@buffer,b); bytestowrite:=bytestowrite-b; result:=b; end else p:=@buffer; if bytestowrite>=BufferSize then begin //empty buffer Flush; //data to write is larger than the buffer, write it directly result:=result+inherited Write(p^,bytestowrite); end else begin //empty buffer Flush; //recurse result:=result+Write(p^,bytestowrite); end; end; end; function TBufferedFS.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; begin if (Origin=soCurrent)and(Offset=0) then result:=inherited seek(Offset,origin)+bufferpos else begin flush; result:=inherited Seek(offset,origin); end; end; } end.