[Back to OOP SWAG index] [Back to Main SWAG index] [Original]
{
This is a relatively simple, fairly small, marginally tested, but extremely
useful object I cooked up last week to provide a familiar interface while
allowing almost a full 64K data buffer on all sorts of typed and untyped
files (except for textfiles--come on, what do you think SetTextBuf is for!).
Enjoy, and please let me know of any bugs, fixes, enhancements, ridicule,
pity, thankfullness, or admiration you might have for me, thanks!
{- FastFile unit: Buffered file I/O object -}
Unit FastFile;
{
Updated 12/1/94
Copyright 1994 by Ryan Thompson, Osiris Development.
You are free to use this code in your programs, however,
it may not be included for-profit software, or source/unit
libraries, without my permission.
Voice: (707)443-4803
FAX: (707)445-0599
BBS: (707)445-0500 v.32terbo/HST
FidoNet: 1:125/37.0
Email: sysop@f37.n125.z1.fidonet.org
}
INTERFACE
Type
FileBuffer = Array[0..$fff0] of byte;
BufFileObj = Object
BufFile : File;
Buf : ^FileBuffer;
IOResult : Integer;
Filename : String;
Open,
Dirty : Boolean;
BufFilePos : Longint;
RecordSize,
BufSize,
BufPosz,
BufTop : Word;
Constructor Init(BufferSize : Word);
Destructor Done;
Procedure Assign(Fname : String);
Procedure Reset(RecSize : Word);
Procedure Rewrite(RecSize : Word);
Procedure Close;
Procedure Rename(Fname : String);
Procedure Erase;
Function EOF : Boolean;
Function FilePos : Longint;
Function FileSize : Longint;
Procedure Seek(Pos : Longint);
Procedure Read(Var V);
Procedure Write(Var V);
Procedure BlockRead(Var V; Count : Word; var Result : Word);
Procedure BlockWrite(Var V; Count : Word; var Result : Word);
Procedure FillBuffer;
Procedure FlushBuffer;
End;
BufferedFile = ^BufFileObj;
IMPLEMENTATION
Constructor BufFileObj.Init(BufferSize : Word);
Begin
Filename:= '';
Open:= false;
Dirty:= false;
BufFilePos:= 0;
RecordSize:= 0;
BufSize:= BufferSize;
BufPos:= 0;
BufTop:= 0;
Getmem(Buf, BufSize);
if Buf = nil then Fail;
End;
Destructor BufFileObj.Done;
Begin
If Open then Close;
if Buf <> nil then Freemem(Buf, BufSize);
End;
Procedure BufFileObj.Assign(Fname : String);
Begin
if Open then Close;
Filename:= FName;
system.Assign(BufFile, Fname);
IOResult:= system.IOResult;
End;
Procedure BufFileObj.Reset(RecSize : Word);
Begin
if Open then Close;
if RecSize = 0
then RecordSize:= 128
else RecordSize:= RecSize;
system.Reset(BufFile, 1);
IOResult:= system.IOResult;
BufFilePos:= 0;
BufPos:= 0;
FillBuffer;
if IOResult = 0
then Open:= true
else Open:= false;
End;
Procedure BufFileObj.Rewrite(RecSize : Word);
Begin
if Open then Close;
if RecSize = 0
then RecordSize:= 128
else RecordSize:= RecSize;
BufTop:= 0;
system.Rewrite(BufFile, 1);
IOResult:= system.IOResult;
if IOResult = 0
then Open:= true
else Open:= false;
End;
Procedure BufFileObj.Close;
Begin
If Dirty then FlushBuffer;
system.Close(BufFile);
IOResult:= system.IoResult;
Open:= false;
End;
Procedure BufFileObj.Rename(Fname : String);
Begin
system.Rename(BufFile, Fname);
IOResult:= system.IOResult;
if IOResult = 0 then Filename:= FName;
End;
Procedure BufFileObj.Erase;
Begin
if Open then Close;
system.Erase(BufFile);
IOResult:= system.IOResult;
End;
Function BufFileObj.EOF : Boolean;
Begin
EOF:= BufFileObj.FilePos >= BufFileObj.FileSize;
End;
Function BufFileObj.FileSize : Longint;
Begin
FileSize:= system.FileSize(BufFile) div RecordSize;
End;
Function BufFileObj.FilePos : Longint;
Begin
FilePos:= (BufFilePos + BufPos) div RecordSize;
End;
Procedure BufFileObj.Seek(Pos : Longint);
Begin
Pos:= Pos * RecordSize;
if (Pos >= BufFilePos + BufSize) or
(Pos < BufFilePos)
then begin
if Dirty then FlushBuffer;
system.seek(BufFile, Pos);
BufFilePos:= Pos;
BufPos:= 0;
FillBuffer;
end
else BufPos:= Pos - BufFilePos;
IoResult:= system.IoResult;
End;
Procedure BufFileObj.Read(Var V);
Var
Overflow : Word;
Begin
If BufPos + RecordSize > BufTop
then begin
Overflow:= BufSize - BufPos;
Move(Buf^[BufPos], V, Overflow);
inc(BufFilePos, BufSize);
BufPos:= 0;
FillBuffer;
Move(Buf^[BufPos], FileBuffer(V)[Overflow], RecordSize - Overflow);
BufPos:= BufPos + RecordSize - Overflow;
end
else begin
Move(Buf^[BufPos], V, RecordSize);
inc(BufPos, RecordSize);
end;
IoResult:= system.IoResult;
End;
Procedure BufFileObj.BlockRead(Var V; Count : Word; var Result : Word);
Begin
Result:= 0;
While (Result < Count) and
(IoResult = 0) and
not EOF
do begin
Read(FileBuffer(V)[Result * RecordSize]);
Inc(Result);
end;
End;
Procedure BufFileObj.Write(Var V);
Var
Overflow : Word;
Begin
Dirty:= true;
If BufPos + RecordSize > BufSize
then begin
Overflow:= BufSize - BufPos;
if Overflow > 0
then Move(V, Buf^[BufPos], Overflow);
BufTop:= BufSize;
FlushBuffer;
inc(BufFilePos, BufSize);
BufPos:= 0;
FillBuffer;
Move(FileBuffer(V)[Overflow], Buf^[BufPos], RecordSize - Overflow);
BufPos:= BufPos + RecordSize - Overflow;
end
else begin
Move(V, Buf^[BufPos], RecordSize);
inc(BufPos, RecordSize);
end;
if BufTop < BufPos
then BufTop:= BufPos;
IoResult:= system.IoResult;
End;
Procedure BufFileObj.BlockWrite(Var V; Count : Word; var Result : Word);
Begin
Result:= 0;
While (Result < Count) and
(IoResult = 0)
do begin
Write(FileBuffer(V)[Result * RecordSize]);
Inc(Result);
end;
End;
Procedure BufFileObj.FillBuffer;
Begin
system.Seek(BufFile, BufFilePos);
system.BlockRead(BufFile, Buf^, BufSize, BufTop);
IoResult:= system.IoResult;
if IoResult = 0 then Dirty:= false;
End;
Procedure BufFileObj.FlushBuffer;
Begin
system.Seek(BufFile, BufFilePos);
system.BlockWrite(BufFile, Buf^, BufTop, BufTop);
IoResult:= system.IoResult;
End;
Begin
End.
{
There is is.... now here's a brief explanation of how to use it:
As you can see, all of the most often-used functions are available in the
object definition. Instead of passing a file handle to the procedures as the
first parameter, the object itself defines the file. The syntax of the
commands is as similar as is possible. The only things to really watch for
are that Reset and Rewrite both require a parameter, and EOF works on all file
types.
Procedure Assign(FName : String);
Procedure Reset(RecSize : Word);
Procedure Rewrite(RecSize : Word);
Procedure Close;
Procedure Rename(Fname : String);
Procedure Erase;
Function EOF : Boolean;
Function FilePos : Longint;
Function FileSize : Longint;
Procedure Seek(Pos : Longint);
Procedure Read(Var V);
Procedure Write(Var V);
Procedure BlockRead(Var V; Count : Word; var Result : Word);
Procedure BlockWrite(Var V; Count : Word; var Result : Word);
A simple program to use these functions would look like the following
untested, off-the-cuff code:
}
Program TestFile;
Uses
FastFile;
Var
InFile,
OutFile : BufferedFile;
Data : Array[1..120] of byte;
Begin
New(InFile, Init($8000)); { Allocate a 32K buffer };
New(OutFile, Init($4000)); { 16K Buffer }
InFile^.Assign(Parameter(1)); { Assign input to a filename }
InFile^.Reset(sizeof(data));
OutFile^.Assign(Parameter(2));
OutFile^.Rewrite(sizeof(data));
While not InFile^.EOF do begin
InFile^.Read(Data);
if Data[1] <> 0 then OutFile^.Write(Data);
end;
InFile^.Close;
OutFile^.Close;
InFile^.Erase;
OutFile^.Rename(Parameter(1));
Dispose(InFile); { Close the file and free the memory }
Dispose(OutFile);
End.
{
As you see, this implements a very silly program which removes the original
after stripping unwanted records from it. Without the large RAM buffers,
this would be an extremely slow, but since all READs and WRITEs and SEEKs and
everything else are done to RAM, few actual disk accesses result. I used
this in a USEnet mail processing program and the speed went from 15K/sec to
130K/sec.
The easiest way to use it is to simply change structures like:
Assign(Filehandle, name); ---> Filehandle^.Assign(name);
...in many cases a couple of Search..Replace passes are all that you need
to modify your software to use this. I've done it will all of my own and
am very pleased.
Again, if you run into any problems, please let me know! I can guarantee
you only that it works fine for me. :-)
}
[Back to OOP SWAG index] [Back to Main SWAG index] [Original]