{$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.