[Back to TEXTFILE SWAG index] [Back to Main SWAG index] [Original]
{$A+,B-,D-,E+,F+,G+,I-,L-,N+,O+,P-,Q-,R-,S-,T-,V-,X-,Y-}
{$M 16384,0,655360}
(*
The problem is as follows:
Q. How to randomly access Large text files, such as tagline files,
in an efficient way.
A. By using an index file which is just a structured file of which
each record is a longint giving us the offset of that line.
The structure can be simple: File of LongInt;
Or a bit more:
OneTagLine = record
offset : longint; {Offset where tag begins in text file}
NumOfLines : byte; {Number of lines in this particular tag}
end;
Ex:
to get Line # 233
Get Record #233 from the Index file.
That value is the offset in the text file
where line 233 begins
To detect changes in the Text file I reserve the first record, record #0,
to conatin the size of the text file at the time of creation of the index.
By checking both the cration date/time of the text file and Record #0
of the index, the program can then determine wether it needs to recreate
the index or not.
*)
program TxtRandR; {Random access to text files}
uses dos;
type
IndexFile = file of longint;
var
Index : IndexFile;
IndexName : string;
N : namestr;
E : extstr;
D : dirstr;
Tags : text;
Line : string;
LineNmbr : word;
LineOfs : longint;
function TextFileSize(var F):longint;
var
OldRecSize : word;
OldMode : word;
Temp : longint;
begin
with filerec(F) do begin
OldMode := mode;
mode := fminout;
OldRecSize := recsize;
recsize := 1;
end;
Temp := filesize(file(F));
with filerec(F) do begin
mode := OldMode;
recsize := OldRecSize;
end;
TextFileSize := Temp;
end;
function TextFilePos(var F):longint;
var
OldRecSize : word;
OldMode : word;
Temp : longint;
begin
with filerec(F) do begin
OldMode := mode;
mode := fminout;
OldRecSize := recsize;
recsize := 1;
end;
Temp := filepos(file(F));
with filerec(F) do begin
mode := OldMode;
recsize := OldRecSize;
end;
TextFilePos := Temp - OldRecSize + textrec(F).bufpos;
end;
procedure CheckIndex(var T:text; var F: IndexFile);
var
Temp : longint;
begin
Seek(F, 0);
if FileSize(F)=0 then
temp := 0
else
Read(F, Temp);
if Temp <> TextFileSize(T) then begin
{
Stored Size is different than that of text file
so rebuild the index file
}
Seek(F,0);
Temp := TextFileSize(T);
write(F, Temp);
while not eof(T) do begin
Temp := TextFilePos(T);
write(F, Temp);
while (not eof(T)) and (not eoln(T)) do
read(T, Line);
readln(T);
end;
Truncate(F);
end;
end;
procedure SeekTextFile(var T; FPos:longint);
var
OldRecSize : word;
OldMode : word;
Temp : longint;
TBuffer : pointer;
BytesRead : word;
begin
with filerec(T) do begin
OldMode := mode;
mode := fminout;
OldRecSize := recsize;
recsize := 1;
end;
Seek(File(T), (FPos div OldRecSize) * OldRecSize);
TBuffer := textrec(T).bufptr;
blockread(File(T), TBuffer^, OldRecSize, BytesRead);
with filerec(T) do begin
mode := OldMode;
recsize := OldRecSize;
end;
textrec(T).bufpos := FPos mod OldRecSize;
textrec(T).bufend := BytesRead;
end;
begin
assign(Tags, paramstr(1));
reset(Tags);
fsplit(paramstr(1), D, N, E);
IndexName := D + N + '.idx';
assign(Index, IndexName);
{$I-}
reset(Index);
{$I+}
if ioresult<>0 then begin
rewrite(Index);
LineOfs := 0;
write(Index, LineOfs);
end;
CheckIndex(Tags, Index);
val(paramstr(2), LineNmbr, LineNmbr);
Seek(Index, LineNmbr);
Read(Index, LineOfs);
SeekTextFile(Tags, LineOfs);
while (not Eof(Tags)) and (not Eoln(Tags)) do begin
read(Tags, Line);
write(Line);
end;
readln(Tags);
writeln;
close(Tags);
close(Index);
end.
[Back to TEXTFILE SWAG index] [Back to Main SWAG index] [Original]