Switch and For Statements, Command Line and File Handling - Direct Access Files

Chapter chap9 section 7

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.


Records and Fields