This page was last updated August, 2004


File I/O


This page address the tasks of reading and writing data on disk. In each case file operations consist of a 3-step process: Open, Access, Close. This page addresses the following types of File Access. The outline below shows the relationship of all the I/O types. Click on any one to jump directly to an explanation and examples of that type or scroll down to read about all the types in sequential order.

  1. Standard C file access
    1. Opening and closing files in C
    2. Standard file access in C
      1. Character
      2. String
      3. Formatted
    3. System or low-level file access in C
      1. Record
      2. Random Access
    4. Handling file I/O errors in C
  2. C++ file access
    1. Opening and closing files in C++
    2. Standard file access in C++
      1. Character
      2. String
    3. System or low-level file access in C++
      1. Binary

Opening and Closing files in C

You must #include <stdio.h> to access all file operations in standard C. All of these file I/O methods can also be used in C++.

To open a file in C you use the fopen command which returns a pointer to a FILE data type:

	FILE *fopen(const char *filename, const char *mode);
filename - character array holding the name of the file to open. This can include the path as well.
mode - character array holding one of the following which tells how you want to open the file. Note that even though some of the modes are single characters this argument must still be passed as a string, i.e. in double quotes.
Most programmers use just "r", "w" or "a" and do the read and write operations in separate functions each of which opens and closes the file. This is safer than leaving a file open while doing internal computations.

Example:

Simple way:
	fptr = fopen("myfile.txt", "r");
This works fine as longs as the file already exists. If not you are in trouble, so the conventional way of opening a file is:

	if ( (fptr=fopen("myfile.txt","r"))==NULL)
	{
	    printf("Can't open file myfile.txt\n");
	    exit();
	}


NOTE: If you want to avoid overwriting a file that already exists you can do the check for !=NULL and if the result is true give a warning that the file already exists. Closing a file in C To close a file that is open call the function fclose() passing in the pointer to the FILE as the only argument.

	fclose(fptr);


Single Character I/O in C

In this type of file I/O single characters are read or written. This is a very inefficient approach and should only be written if each character must be checked in some way while reading or writing. There are two functions used. The first is for reading a character from an open file and the second is for writing a character to an open file.

     char fgetc(FILE *);      // Reads one character from a file
     char fputc(int, FILE *); // Writes one character to a file.  
                              //   Note the character is treated as an integer.
Below is a simple demonstration program that opens a file for writing characters and writes out what is typed at the keyboard until the Enter enter key is pressed. It then closes the file and immediately reopens it for reading. All characters are read from the file and displayed on the screen.
#include <stdio.h>

int main(void)
{
    FILE *fptr;        // pointer to FILE
    char ch;
    //-----------------------------------------------
    //  Writing characters to a file
    //  I/O function:  int fputc(int ch, File *fptr)
    //-----------------------------------------------
    // Open the file for writing
    fptr=fopen("textfile.txt","w");
    // Write keyboard characters till user presses Enter
    while ( (ch = getc(stdin)) != '\n')
        fputc(ch, fptr);

    // Close the file
    fclose(fptr);

    //-----------------------------------------------
    //  Reading characters from a file
    //  I/O function:  int fgetc(File *fptr)
    //-----------------------------------------------
    if( (fptr = fopen("textfile.txt","r")) == NULL)
        {
            printf("Can't open textfile.txt.\n");
            return 0;
        }
    while ( (ch = fgetc(fptr)) != EOF)
        printf("%c", ch);
    fclose(fptr);
    return 0;
}
Note: EOF = -1, this is not a character stored on the disk. It is a flag transmitted by the operating system when it realizes it has read the last character in a file. Since all ASCII characters have an integer value of 0...255 then -1 is unique and can be recognized as EOF. This is also why ch is read by getc() as an int type not a char type.

String I/O in C

This type of I/O reads and writes whole strings on single lines to a file. There are two functions used. The first is for reading a string/line from an open file and the second is for writing a string/line to an open file.

     char *fgets(char *s, int n, FILE *); // Reads at most n-1 characters into 
                                             // char array s and terminates it with a '\0'.  
                                             // NOTE: The newline character '\n' is read in as 
                                             // part of the string.  See how to handle this below.
     int fputs(const char*, FILE *);  // Writes a string to a file.
The following sample program writes strings which are typed at the keyboard to the file. It terminates when the <>B>Return key is pressed alone. The file is then closed and reopened to read all strings/lines from the file and print them on the screen.
#include <stdio.h>
#include <string.h>

int main(void)
{
    FILE *fptr;        // pointer to FILE
    char string[81];     // Use 80 char lines
    fptr = fopen("textfile.txt","w");
    //-----------------------------------------------
    //  Writing strings to a file
    //  I/O function:  int fputs(char *string, File *fptr)
    //-----------------------------------------------
    while (strlen(gets(string)) > 0)
    {
        fputs(string, fptr); // write string
        fputs("\n", fptr);   // write newline 
    }
    fclose(fptr);
    //--------------------------------------------------------------------------
    //  Reading strings from a file
    //  I/O function:  char *fgets(char *string, int n, File *fptr)
    //--------------------------------------------------------------------------
    if((fptr = fopen("textfile.txt","r"))==NULL)
    {
        printf("Can't open textfile.txt.\n");
        return 0;
    }
    while (fgets(string,80,fptr) != NULL)
    {
        string[strlen(string)-1] = '\0';
        printf("%s\n", string);
    }
    fclose(fptr);
    return 0;
}
Note the use of the string input function gets(). Also, note that the '\0' is not written to the file so you must explicitly put in a newline character ('\n') to separate the strings. When the string is read back in the newline character is read in with it and becomes a part of the string. To remove the newline character use string[strlen(string)-1] = '\0'; which overwrites the newline character with another null terminator ('\0').

Formatted I/O in C

Formatted I/O reads and writes formatted data in the same form as scanf() and printf(). There are two functions used. The first is for reading formatted data from an open file and the second is for writing formatted data to an open file.
     fscanf(ptr,"format specifier", varlist); 	// Reads specified variables from disk
     fprintf(ptr,"format specifier", varlist);  // Writes specified variables to disk
Note: This writes the data out in text format so you can open the file and read it with any word processor.

The following example reads an int, a float, and a string from the keyboard and writes them to disk. It terminate when the first number is 0. The file is then closed and reopened to read the data back from textfile.txt and print it on the screen.
#include <stdio.h>
#include <string.h>
int main(void)
{
    int inum;
    float fnum;
    char string[81];
    FILE *fptr;
    fptr = fopen("textfile.txt", "w");
    //-----------------------------------------------------------
    //  Writing formatted data to a file
    //  I/O function:  int fprintf(File *fptr, char *format,...)
    //-----------------------------------------------------------
    do
    {
        printf("Type int, float, and string: ");
        scanf("%d %f %s", &inum, &fnum, string);
        fprintf(fptr,"%d %f %s\n",inum,fnum,string);
    }
    while (inum != 0);
    fclose(fptr);

    //-------------------------------------------------------------------
    //  Reading formatted data from a file
    //  I/O function:  int fscanf(File *fptr, char *format,...)
    //-------------------------------------------------------------------
    if((fptr=fopen("textfile.txt","r"))==NULL)
    {
        printf("Can't open textfile.txt.\n");
        return 0;
    }
    while(fscanf(fptr,"%d %f %s", &inum, &fnum, string) != EOF)
        printf("%d %f %s\n",inum,fnum,string);
    fclose(fptr);
    return 0;
}

Note when you write to disk using formatted I/O you must explicitly include the white space delimiters between values.

Record I/O in C (Reading and Writing whole structures)


Record or binary I/O in C allows you to read and write whole blocks of data at one time. This is usually used to read and write whole structures and arrays to disk. There are two functions used. The first is for reading blocks of data from an open file and the second is for writing blocks of data to an open file.
     fread(&object, sizeof(object), n, fptr);  // Reads n blocks of size sizeof(object) 
                                               // into object.  Unless object is an array n=1.
     fwrite(&object, sizeof(object), n, fptr); // Writes n objects of size sizeof(object) 
                                               // starting at &object.
The following example reads data from the keyboard, places it in a simple data structure, and writes the structure to disk. The program then closes the file and reopens it to reads simple structures from disk and print them on the screen.
#include <stdio.h>

// Define a simple data structure
struct simple
{
    int num;
    char ch;
};

int main(void)
{
    FILE *fptr;        // pointer to FILE
    simple sim;
    char ch;

    fptr=fopen("structfile.bin", "wb");
    //----------------------------------------------------------------
    //  Writing structures to a file
    //  I/O function:  long fwrite(void *buffer, long size,
    //                           long numObjects, FILE *fp)
    //-----------------------------------------------------------------
    do
    {
        printf("Type an int and a char.\n");
        scanf("%d %c", &sim.num, &sim.ch);
        fwrite(&sim, sizeof(struct simple), 1, fptr);
        printf("Add another structure to disk(y/n)?  ");
        fflush(stdin); // Flush the keyboard buffer
        ch = getc(stdin);
    }
    while(ch =='y');

    fclose(fptr);
    //------------------------------------------------------
    //  Reading structures from a file
    //  I/O function:  long fread(void *buffer, long size,
    //                           long numObjects, FILE *fp)
    //------------------------------------------------------
    if( (fptr = fopen("strufile.bin", "rb")) == NULL)
    {
        printf("Can't open structfile.bin.\n");
        return 0;
    }
    while (fread(&sim, sizeof(struct simple), 1, fptr)==1)
        printf("%d %c\n", sim.num, sim.ch);
    fclose(fptr);
    return 0;
}
Note: fread() returns an integer value equal to the number of blocks read, ie. if we ask for one structure and fread() returns 0 we know we have reached the end of the file because there was no structure left to read.

Random Access files in C

The functions fread() and fwrite() discussed in the previous section can also be used to create random access files. These are files in which you can seek to a particular record in the file and read or write that one file without touching all other records in the file. This is dependent on using records (structures) on only one type, i.e. all the same size. With files of structures you can randomly access the stored structures using the fseek() function.

	int fseek(FILE *fptr, long offset, int mode);
fptr - pointer to FILE.
offset - the number of bytes to move from the current position in the file. fseek() uses a "file pointer", ie. it points to the next position to be read from or written to in the file. Don't confuse this with pointers to type FILE such as *fptr.
mode - the direction in which to move.

Example:

Handling file I/O errors in C

Error Handling
There are a couple of handy error handling functions that you might find useful in file handling.
  1. ferror(fptr); Takes a pointer to a file as its argument and returns 0 (TRUE) if no error occured, or non-zero (FALSE) if some error occurred.
  2. perror("Error message"); Takes a string that you supply which usually indicates where the error occurred. It prints this string and then it prints a system level error message.
    Example: Use after a read or write operation
    		if ( ferror(fptr) )     // If error
    		{
    			perror("Disk access error!");   // Report it
    			fclose(fptr);                   // Close file
    			exit();                         // And exit
    		}
    	

Opening and Closing files in C++

C++ introduces the concept of streams in file I/O. A stream is just a "flow" of characters.

#include to access all file operations in standard C++

Opening a file in C++ can be done with either of the following functions:

fstream open(const char *filename, int mode);
ifstream open(const char *filename); // Open for input by default
ostream open(const char *filename); // Open for output by default
filename - character array holding the name of the file to open. This can include the path as well. mode - Integer defining how the file is to be opened. This can be Examples: Any of these will open a file for writing

ofstream outfile; // Declare an ofstream reference

outfile = open("myfile.txt", ofstream::out);
outfile = open("myfile.txt", ios::out);
outfile = open("myfile.txt");

Any of will these will also open a file for writing

fstream outfile; // Declare an fstream reference

outfile = open("myfile.txt", ofstream::out);
outfile = open("myfile.txt", ios::out);

In C++ as in C it is a good idea to check and see if the file was successfully opened. In C++ it is done like this:
	if (!outfile.is_open())
	{
		cout << "Can't open file myfile.txt\n";
		exit();
	}

Any of these will open a file for reading

ifstream infile; // Declare an ifstream reference

infile = open("myfile.txt", ofstream::in);
infile = open("myfile.txt", ios::in);
infile = open("myfile.txt");

Any of will these will also open a file for reading

fstream infile; // Declare an fstream reference

infile = open("myfile.txt", ofstream::in);
infile = open("myfile.txt", ios::in);

When opening a file for reading it is also a good idea to check to make sure the file was successful opening:
	if (!infile.is_open())
	{
		cout << "Can't open file myfile.txt\n";
		exit();
	}

Closing a file in C++
To close a file call the close() function that is part of the file object.


	outfile.close();
	infile.close();

Single Character I/O in C++

In this type of file I/O single characters are read or written. This is a very inefficient approach and should only be written if each character must be checked in some way while reading or writing. There are two functions used. The first is for reading a character from an open file and the second is for writing a character to an open file.

     char infile.get();      // Reads one character from a file
     void outfile.put(char ch); // Writes one character to a file.  
Below is a simple demonstration program that opens a file for writing characters and writes out the alphabet. It then closes the file and immediately reopens it for reading. All characters are read from the file and displayed on the screen.
#include <fstream.h>

int main(void)
{
    ofstream outfile;   // Output file stream
    ifstream infile;    // Input file stream
    char ch;

    outfile.open("textfile.txt", ofstream::out);
    //-----------------------------------------------
    //  Writing characters to a file
    //  I/O function:  outfile.put(char ch)
    //-----------------------------------------------
    for(ch='a'; ch<='z'; ch++)
    {
        outfile.put(ch);
    }
    outfile.close();

    //-----------------------------------------------
    //  Reading characters from a file
    //  I/O function:  char infile.get()
    //-----------------------------------------------
    infile.open("textfile.txt", ifstream::in);
    cout << "Characters read from file.\n";
    while (infile.good())
    {
        ch = infile.get();
        cout << ch;
    }
    cout << "\n";
    infile.close();
    return 0;
}

String I/O in C++

This type of I/O reads and writes whole strings on single lines to a file. There are two functions used. The first is for reading a string/line from an open file and the second is for writing a string/line to an open file.

     infile.getline(char string[], int n); // reads up to n characters into 
                                       // char array string and terminates it with a '\0'.  
                                       // Stops reading if a newline character is found.  
                                       // Does not read the newline.
     outfile.write(char string[], int n);  // writes a string of n characters to 
                                      // a file from the character array.
The following sample program writes some test strings to the file. The file is then closed and reopened to read all strings/lines from the file and print them on the screen.
#include <fstream.h>
int main(void)
{
    ofstream outfile;    // Output file stream
    ifstream infile;    // Input file stream
    char line[81];     // Use 80 char lines

    outfile.open("textfile.txt", ofstream::out);
    //------------------------------------------------------------------------
    //  Writing strings to a file
    //  I/O function:  outfile.write(char *string, int numChars)
    //------------------------------------------------------------------------
    for(int i=0; i<10; i++)
    {
        outfile.write("Testing writing to file\n", 24);
    }
    outfile.close();

    infile.open("textfile.txt", ifstream::in);
    //------------------------------------------------------------------------
    //  Reading strings from a file
    //  I/O function:  infile.getline(char *string, int maxChars)
    //------------------------------------------------------------------------
    while (infile.good())
    {
        infile.getline(line, 80);  
        cout << line << "\n"; 
    }
    infile.close();
    return 0;
}

Binary I/O in C++

There are two approaches for using binary file I/O in C++. The first uses the overloaded operators << and >>.

The following example writes some numbers in binary format to a file. It then closes the file and reopens it for reading. It then read the numbers in binary format from the file.
#include <fstream.h>

int main(void)
{
    ofstream outfile;    // Output file stream
    ifstream infile;    // Input file stream
    int num;

    outfile.open("binfile.dat", ofstream::binary);
    //-----------------------------------------------
    //  Writing numerical data as binary to a file
    //  I/O function:  Overloaded << operator
    //-----------------------------------------------
    for(int i=0; i<10; i++)
    {
        outfile << i << " \n";
    }
    outfile.close();

    infile.open("binfile.dat ", ifstream::binary);
    //-----------------------------------------------
    //  Reading numerical data as binary from a file
    //  I/O function:  Overloaded >> operator
    //-----------------------------------------------
    while (infile.good())
    {
        infile >> num;
        if(infile.good()) cout << num << " \n";
    }
    infile.close();
    return 0;
}

The second approach to binary I/O in C++ reads and writes whole structures.

In the example below we write some structures in binary format to a file. The file is then closed and reopened for reading. Then we read the structures in binary format from the file and print the data on the screen.
#include <fstream.h>
struct simple
{
    int x;
    char ch;
};

int main(void)
{
    ofstream outfile;    // Output file stream
    ifstream infile;    // Input file stream
    simple sim1;

    outfile.open("StructBin.dat", ofstream::binary); 
    if(!outfile.is_open())
    {
       cout << "Unable to open file for output." 
               << "Program terminating.\n";
       return 0;
    }
    //--------------------------------------------------------
    //  Writing structures in binary to a file
    //  I/O function:  outfile.write(const char *, int size)
    //--------------------------------------------------------
    for(int outst=0; outst<10; outst++)
    {
       sim1.x = outst;
       sim1.ch = 'a' + outst;
    // Write 1 structure to the file. Note: the write() function 
    // expects a const *char as the first argument.  We use the 
    // reinterpret_cast operator to cast the structure pointer to a 
    // *char.
       outfile.write(reinterpret_cast<const char *>(&sim1), 
                    sizeof(simple));  
    }
    outfile.close();

    infile.open("StructBin.dat", ifstream::binary);
    if(!infile.is_open())
    {
        cout << "Unable to open file for input." <<
                     "Program terminating.\n";
        return 0;
    }

    //--------------------------------------------------------
    //  Reading structures in binary from a file
    //  I/O function:  infile.read(char *, int size)
    //--------------------------------------------------------
    while(!infile.eof()) 
    {
        infile.read(reinterpret_cast<char *>(&sim1), 
            sizeof(simple));
        if(!infile.eof())
            cout << sim1.x << " -- " << sim1.ch << "\n";  
    }
    infile.close();
    return 0;
}