
 Area: FC_prog 
  Msg#: 1741                                         Date: 04-02-96  06:13
  From: Matthew Probert                              Read: Yes    Replied: No 
    To: All                                          Mark:                     
  Subj: C File I/O - Advanced

                                  C FILE I/O

                               Matthew Probert

                              Servile  Software


                              ADVANCED FILE I/O



So far our file I/O has been limited to sequential files. Now it is time to 
forge ahead with random access files. 

A random access file is one in which data can be read or written in any 
position within the file. It is perhaps best illustrated by a practical 
example. Consider a disk file containing names and addresses: 

+---------+---------+---------+---------+
|Record 1 |Record 2 |Record 3 |Record n |
+---------+---------+---------+---------+

The individual records are arranged in the order in which they were written 
to the file. When a stream is opened and assigned to the file, a pointer is 
set to the current file position. This position will either be the start of 
record 1 or, if the stream was opened in append mode it will be the end of 
the file. When a read operation occurs on the stream, data is read from the 
current file position, and the pointer moved towards the end of the file. 

Using sequential file access, records are read in order, 1,2,3 etc. This is 
not very efficient when the program wants to only read a single record from 
the middle or towards the end of the file since many unwanted records have 
to be read first. 

Random file access allows the program to move the current file position 
pointer to any location within the file without reading unwanted records. 

The standard C library provides a function, fseek() which sets the file 
position pointer of a specified stream to a desired location. fseek() 
accepts three parameters; a FILE pointer to the open stream, a long offset, 
and an integer from whence to move the file position pointer. fseek() has 
the prototype; 

    int fseek(FILE *fp, long offset, int whence)

If fseek() cannot move the file pointer to the desired location, it returns 
non-zero. 

Stdio.h defines three macros relating to 'whence'; SEEK_SET the beginning of 
the file, SEEK_CUR the current file pointer position, and SEEK_END the end 
of the file. 

To move a file pointer to the start of an open stream you can use the 
command; 

        fseek(fp,0,SEEK_SET);

Notice the offset is zero, that is move the file pointer on stream 'fp' to 
zero bytes from the start of the file. 

Associated with fseek() is the standard C library function ftell() which 
returns the position of a file pointer. It accepts just one parameter, a 
FILE pointer to an open stream and has the prototype; 

        long int ftell(FILE *fp)


The following example program illustrates the use of ftell();

#include <stdio.h>

main()
{
    FILE *fp;
    int result;
    long position;

    /* Create a file called 'myfile.txt' and open it read/write access */
    fp = fopen("myfile.txt","w+");

    /* Check the result of the open function */
    if (fp == NULL)
        printf("\nUnable to open file\n");
    else
    {
        /* Write to the file */
        result = fputs("Hello file!",fp);

        /* Check result of write */
        if (result == EOF)
            printf("\nError writing to file.");

        /* Get file pointer position */
        position = ftell(fp);
        printf("\nThe file pointer is at position %ld",position);

        /* Close the file */
        fclose(fp);
    }
}

We can use fseek() and ftell() to find the length of a file;

#include <stdio.h>

main()
{
    FILE *fp;
    int result;
    long position;

    /* Create a file called 'myfile.txt' and open it read access */
    fp = fopen("myfile.txt","r");

    /* Check the result of the open function */
    if (fp == NULL)
        printf("\nUnable to open file\n");
    else
    {
        /* Move file pointer to end-of-file */
        fseek(fp,0,SEEK_END);

        position = ftell(fp);
        printf("\nThe file pointer is at position %ld",position);

        /* Close the file */
        fclose(fp);
    }
}

Having covered random file access it is time to consider records. The 
reality is that almost all commercial data applications use files divided 
into records. A record being a single data entry comprised of a number of 
fields of sub-information. For example, going back to a name and address 
file this is comprised of records, each record being one person's details. 
Each record is then divided into fields of personal information. For 
example; name, address, town, county, post code and telephone number. 
Accessing a file of this nature using string or single byte transfer would 
be laborious and impractical. Instead we can make use of the standard C 
library fread() and fwrite() functions. 

fread() is used to read one or more fixed length records of data from a 
stream. It accepts four parameters; a pointer to a buffer in which to store 
the read data, the size of each record, the number of records to read and a 
FILE pointer to the open stream. It has the prototype; 

        size_t fread(void *buffer,size_t size, size_t num,FILE *fp);


fread() returns the number of records actually read. This will be different 
from 'num' when an error occurs.

fwrite() takes the same parameters as fread() and as such has the same 
prototype. The difference being that it attempts to write the records stored 
in the area of RAM pointed to by 'buffer' to the open stream. 

The following program illustrates the use of fwrite();

#include <stdio.h>
#include <string.h>

/* Structure for record data */
typedef struct
{
    char name[31];
    char address[31];
    char town[31];
    char county[31];
    char post[13];
    char telephone[16];
}
data;

data record;

main()
{
    FILE *fp;

    fp = fopen("data.txt","w+");

    if (fp == NULL)
        printf("\nUnable to create data file");
    else
    {
        strcpy(record.name,"John Smith");
        strcpy(record.address,"22 Old street");
        strcpy(record.town,"Birmingham");
        strcpy(record.county,"Midlands");
        strcpy(record.post,"BG1 7HH");
        strcpy(record.telephone,"021 768 4231");

        if(fwrite(&record,sizeof(record),1,fp) != 1)
            printf("\nError writing data to file");
        fclose(fp);
    }
}


... [Servile Info Journal]
___ Blue Wave/QWK v2.12
