Skip to main content
Engineering LibreTexts

13.1: Introduction

  • Page ID
    35864
  • High level fileio in C uses functions such as fopen(), fclose(), fread(), fwrite, fprintf(), fgetc(), and so on. These utilize a variable of type FILE to access disk files. They allow you to read and write data from/to files on disk in a manner very similar to sending data to the computer screen via printf() or retrieving data from the keyboard via scanf().

    Closer to home, we have low level fileio. These use a file descriptor, which is basically just an integer. High level functions actually call the low level functions anyway. There are five things you need to do with files. First, you open them to obtain access to an existing file or to create a new one. Next, you read or write data from/to the file. You may also need to move around in a file, perhaps to reread data or to skip over data. Finally, when you are finished using the file, you must close it. To open a file use:

    fh = open( name, mode );
    

    where

    char *name: /* disk name of file */
    int fh:     /* file descriptor */
    int mode;   /* a define */
    

    fh is the file descriptor that is needed for subsequent read/write calls. It will be >= O if all is OK, -1 on error.

    Example modes:

    O_RDONLY

    read only

    O_WRONLY

    write only

    O_CREAT

    create if not exists

    To read/write data, use:

    count = read( fh, buffer, len );
    count = write( fh, buffer, len );
    

    fh is the file descriptor returned from open(), buffer is the address of where to find/place data (i.e., the thing you’re copying to disk or making a copy of from disk), len is the number of bytes to read/write, count is the actual number of bytes read/written.

    A common construct is:

    if( (count = read( fh, buf, len )) != len )
    {
        //...there was an error, process it...
    }
    

    You can also skip around in a file:

    apos = lseek( fh, rpos, mode );
    

    where

    long apos

    absolute position (-1 on error)

    long rpos

    relative position

    mode

    0 for relative to beginning of file (rpos >= 0)

    1 for relative to current position

    2 for relative to the end (rpos <= 0)

    Note that your present position is = lseek( fh, O, 1 );

    When you are done with the file, you must close it:

    error = close( fh );
    

    error is O if all went OK, -1 otherwise.

    C allows you to have multiple files open simultaneously for reading and writing. You will need one file descriptor for each file open at the same time (they can be reused later, if desired).

    Below is a program that can be used to investigate the contents of almost any kind of file. It uses a variety of techniques that we have examined through the course. Some lines have wrapped.

    /* headdump.c
       This program spits out the first 128 bytes of a file in hex, decimal, and
       string form (non printable chars are printed out as periods). */
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <ctype.h>
    
    #define CHUNKSIZE 128
    
    unsigned char buf[CHUNKSIZE];
    
    char *szerrmsgs[] = {
        "No errors on %s\n",
        "USAGE: %s <filename>\n",
        "Could not open %s\n",
        "Seek error on %s\n",
        "Position error on %s\n",
        "Rewind error on %s\n",
        "Read error on %s\n"
        };
    
    void my_exit( FILE *fp, int err, char *pc )
    {
       if( fp )    fclose( fp );
       if( err )   printf( szerrmsgs[err], pc ); /* don't bother if all OK */
       exit( err );
    }
    
    void main( int argc, char *argv[] )
    {
        int size, c=0, x;
        FILE *fp=0;
        
        if( (argc < 2) || ( !strcmp(argv[1], "?") ) )
            my_exit( fp, 1, argv[0] );
    
        if( fp = fopen( argv[1], "r" ) )
        {
            /* Find out how big the file is. If it's < CHUNKSIZE then read in what's available */
            if( -1 != fseek( fp, 0, 2 ) ) /* seek to end */
            {
                if( -1 != (size = ftell( fp )) )
                {
                    if( size > CHUNKSIZE ) size = CHUNKSIZE;
                    if( -1 != fseek( fp, 0, 0 ) ) /* seek to start */
                    {
                        if( fread( buf, 1, size, fp ) == (unsigned int)size )
                        {
                            /* print this out as 8 chars by 16 (or so) lines, first hex,
                             then decimal, then string */
                            while( c < size )
                            {
                                /* print out line as hex */
                                printf("%3d: %02x%02x %02x%02x %02x%02x %02x%02x ",
                                c,buf[c],buf[c+1],buf[c+2],buf[c+3],buf[c+4],buf[c+5],buf[c+6],buf[c+7] );
                            
                                /* print out line as decimal */
                                printf(" %03d%03d %03d%03d %03d%03d %03d%03d ",
                                buf[c],buf[c+1],buf[c+2],buf[c+3],buf[c+4],buf[c+5],buf[c+6],buf[c+7] );
    
                                /* print out line as string. check the chars and if not
                                    printable, replace with periods */
                                for( x=0; x<8; x++ )
                                {
                                    if( !isprint( buf[c+x] ) )
                                        buf[c+x] = '.';
                                }
                                printf(" %c%c%c%c%c%c%c%c\n",buf[c],buf[c+1],buf[c+2],
                                buf[c+3],buf[c+4],buf[c+5],buf[c+6], buf[c+7] );
    
                                c+=8;
                            }
                        }
                        else
                            my_exit( fp, 6, argv[0] );
                    }
                    else
                        my_exit( fp, 5, argv[0] );
                }
                else
                    my_exit( fp, 4, argv[0] );
            }
            else
                my_exit( fp, 3, argv[0] );
        }
        else
            my_exit( fp, 2, argv[1] );
        my_exit( fp, 0, argv[1] );
    }