Standard File I/O
The C standard library I/O functions allow you to read and write data to both files and devices. There are no predefined file structures in C, all data being treated as a sequence of bytes. These I/O functions may be broken into two different categories : stream I/O and low-level I/O.
The stream I/O functions treat a data file as a stream of individual characters. The appropriate stream function can provide buffered, formatted or unformatted input and output of data, ranging from single characters to complicated structures. Buffering streamlines the I/O process by providing temporary storage for data which takes away the burden from the system of writing each item of data directly and instead allows the buffer to fill before causing the data to be written.
The low-level I/O system on the other hand does not perform any buffering or formatting of data –instead it makes direct use of the system’s I/O capabilities to transfer usually large blocks of information.
Binary Streams
A binary stream is a sequence of data comprised of bytes that will not be interfered with so that a one-to-one relationship is maintained between data sent and data received.
Common File Functions
| fopen() | open a stream |
| fclose() | close a stream |
| putc()& fputc() | write a character to a stream |
| getc()& fgetc() | read a character from a stream |
| fprintf()& fscanf | formatted I/O |
| fgets() & fputs() | string handling |
| fseek() | position the file pointer at a particular byte |
| feof() | tests if EOF |
Opening and Closing Files
A stream is associated with a specific file by performing an open operation. Once a file is opened information may be exchanged between it and your program. Each file that is opened has a unique file control structure of type FILE ( which is defined in <stdio.h> along with the prototypes for all I/O functions and constants such as EOF (-1) ). A file pointer is a pointer to this FILE structure which identifies a specific file and defines various things about the file including its name, read/write status, and current position. A file pointer variable is defined as follows
FILE *fptr ;
The fopen() function opens a stream for use and links a file with that stream returning a valid file pointer which is positioned correctly within the file if all is correct. fopen() has the following prototype
FILE *fopen( const char *filename, const char *mode );
where filename is a pointer to a string of characters which make up the name and path of the required file, and mode is a pointer to a string which specifies how the file is to be opened. The following table lists some values for mode.
| r | opens a text file for reading (must exist) |
| w | opens a text file for writing (overwritten or created) |
| a | append to a text file |
| rb | opens a binary file for reading |
| wb | opens a binary file for writing |
| ab | appends to a binary file |
| r+ | opens a text file for read/write (must exist) |
| w+ | opens a text file for read/write |
| a+ | append a text file for read/write |
| rb+ | opens a binary file for read/write |
| wb+ | opens a binary file for read/write |
| ab+ | append a binary file for read/write |
If fopen( ) cannot open “test.dat ” it will a return a NULL pointer which should always be tested for as follows.
FILE *fp ;
if ( ( fp = fopen( “test.dat”, “r” ) ) == NULL )
{
puts( “Cannot open file”) ;
exit( 1) ;
}
This will cause the program to be exited immediately if the file cannot be opened.
The fclose() function is used to disassociate a file from a stream and free the stream for use again.
fclose( fp ) ;
fclose() will automatically flush any data remaining in the data buffers to the file.
Reading & Writing Characters
Once a file pointer has been linked to a file we can write characters to it using the fputc() function.
fputc( ch, fp ) ;
If successful the function returns the character written otherwise EOF. Characters may be read from a file using the fgetc() standard library function.
ch = fgetc( fp ) ;
When EOF is reached in the file fgetc( ) returns the EOF character which informs us to stop reading as there is nothing more left in the file.
Example :- Program to copy a file byte by byte
#include <stdio.h>
void main()
{
FILE *fin, *fout ;
char dest[30], source[30], ch ;
puts( “Enter source file name” );
gets( source );
puts( “Enter destination file name” );
gets( dest ) ;
if ( ( fin = fopen( source, “rb” ) ) == NULL ) // open as binary as we don’t
{// know what is in file
puts( “Cannot open input file “) ;
puts( source ) ;
exit( 1 ) ;
}
if ( ( fout = fopen( dest, “wb” ) ) == NULL )
{
puts( “Cannot open output file “) ;
puts( dest ) ;
exit( 1 ) ;
}
while ( ( ch = fgetc( fin ) ) != EOF )
fputc( ch , fout ) ;
fclose( fin ) ;
fclose( fout ) ;
}
fread() and fwrite()
These two functions are used to read and write blocks of data of any type. Their prototypes are as follows where size_t is equivalent to unsigned.
size_t fread( void *buffer, size_t num_bytes, size_t count, FILE *fp ) ;
size_t fwrite( const void *buffer, size_t num_bytes, size_t count, FILE *fp ) ;
where buffer is a pointer to the region in memory from which the data is to be read or written respectively, num_bytes is the number of bytes in each item to be read or written, and count is the total number of items ( each num_bytes long ) to be read/written. The functions return the number of items successfully read or written
For Example :-
#include <stdio.h>
#include <stdlib.h>
struct tag {
float balance ;
char name[ 80 ] ;
} customer = { 123.232, “John” } ;
void main()
{
FILE *fp ;
double d = 12.34 ;
int i[4] = {10 , 20, 30, 40 } ;
if ( (fp = fopen ( “test.dat”, “wb+” ) ) == NULL )
{
puts( “Cannot open File” ) ;
exit(1) ;
}
fwrite( &d, sizeof( double ), 1, fp ) ;
fwrite( i, sizeof( int ), 4, fp ) ;
fwrite( &customer, sizeof( struct tag ), 1, fp ) ;
rewind( fp ) ; /* repositions file pointer to start */
fread( &d, sizeof( double ), 1, fp ) ;
fread( i, sizeof( int ), 4, fp ) ;
fread( &customer, sizeof( struct tag ), 1, fp ) ;
fclose( fp ) ;
}