The C language view of a file is to see it as an array of bytes. This means that all files may be treated as direct access files and the library function fseek() may be used to provide immediate access to any particular part of the file. This assumes that the start byte address of the record is known. The following program demonstrates the construction and use of a table of record start positions using ftell().
/* program to display selected
records from a file */
#include <stdio.h>
#define MAXREC 1000
long index[MAXREC];
int makeindex(FILE *);
void showrec(FILE *,int);
main(int argc, char *argv[])
{
int nrec; /* record to show */
int nrecs; /* records in file */
FILE *d; /* the data file */
if(argc != 2)
{
fprintf(stderr,"Usage : showrec f\n");
exit(1);
}
if((d=fopen(argv[1],"r"))==NULL)
{
fprintf(stderr,"error opening %s\n",
argv[1]);
exit(1);
}
if((nrecs=makeindex(d))==0)
{
fprintf(stderr,
"file too big or empty\n");
exit(1);
}
printf("%d records\n",nrecs);
while(1)
{
printf("Enter record number ");
scanf("%d",&nrec);
if(nrec<0) exit(0);
if(nrec >= nrecs)
printf("Out of range\n");
else showrec(d,nrec);
}
}
int makeindex(FILE *f)
/* builds the (global) index table
and returns the number of records
or 0 if the file has too many
records or is empty
*/
{
int c;
int i=0;
while(1)
{
if((c=getc(f))=='\n')
{
index[++i]=ftell(f);
if(i==MAXREC) return 0;
}
else
if(c==EOF) return i;
}
}
void showrec(FILE *f, int n)
/* display required record - simply copies
characters to stdout
*/
{
char c;
fseek(f,index[n],0);
while(1)
{
putchar((c=getc(f)));
if(c=='\n') return;
}
}
A typical dialogue using the source file as input is shown below.
$ fil3 fil3.c
76 records
Enter record number 44
or 0 if the file has too many
Enter record number 11
FILE *d; /* the data file */
Enter record number 76
Out of range
Enter record number 21
exit(1);
Enter record number -1
There are a number of interesting points here. The direct access functions always work with long integers and it is traditional to declare the associated variables as being of type
long int .
The record numbering starts at zero and the file examination part of the program is terminated by a negative input. Strictly the final parameter of
fseek()
ought to have been
SEEK_SET
not zero. The value returned by ftell() is the byte position of the byte about to be read from the file so when a newline is encountered this is the start address of the next record.
The functions fsetpos() and fgetpos() do the same things as fseek() and ftell() only they use parameters of type fpos_t rather than long int. This, potentially, allows for larger files to be handled and the use of these functions is to be preferred.