Broad Network


Basics of Accessing Files in C++

C++ Taking the Bull by the Horns – Part 25

Forward: In this part of the series, we see how to access files in C++.

By: Chrysanthus Date Published: 22 Aug 2012

Introduction

This is part 25 of my series, C++ Taking the Bull by the Horns. In this part of the series, we learn how to access files in C++. I assume that you have read the previous parts of the series before reaching here, because the knowledge here is based on knowledge gained from the previous parts. We shall consider only text files and those, which are in the working directory (so we shall not need to bother about directory path). This means that your test code should remain in the working directory.

Note: If you cannot see the code or if you think anything is missing (broken link, image absent), just contact me at forchatrans@yahoo.com. That is, contact me for the slightest problem you have about what you are reading.

File Classes and Streams
In order for you to use a file in the hard disk or some other drive, you have to do what is called opening the file. For this, the content of the file is copied into memory. This area in memory that has the content of the file is called a stream (precisely a buffer). Whatever you want to do to the file (modifying the file, adding text to the end of the file, or just reading the file) you do to the stream. After that you have to do what is called closing the file.  When a file is closed, the content of the stream is copied to the file in the disk, if necessary. Any modification of stream content or adding of text to the end of the stream is reflected in the file in the disk after closing.

A file may not exist in the disk. This means you have to create it. For this purpose, you still have to use the opening process (see below). A stream for the newly (not existing) opened file is created. You send information to the stream. When you close the file, effectively closing the stream, the content of the stream is copied to the disk for the first time. Closing a file means putting an end to the association between the stream and the corresponding file in the disk, after the content of the stream has just been copied to the file, which might or might not have existed, in the disk.

Note: the content of the stream is the file content copied from disk, if the file existed in the disk before it was opened.

There are three classes, which are used to access files. These classes are predefined; you do not have to define them (type them out). The names of these classes are ofstream, ifstream and fstream. When an object is created from any of these classes, a stream in memory is associated with the object.

To use these classes you need to include a header file called the fstream header in your program. Once this header has been included in you program file, you just instantiate objects of type, ofstream, ifstream or fstream as if you had typed out the classes yourself. Of course, these classes have methods that you use to access the streams of the corresponding created (instantiated) objects.

open and close Methods
Each of the above three classes has an open and a close method. The syntax for the open method is,

    streamObj.open(filename, mode);

streamObj is the object created from one of the classes.  This is followed by a dot and then you have the opened method call. The first argument in the parentheses is the file name in double quotes. I will explain the role of the mode (second) argument as we go along. The mode argument is optional; that is, you do not have to use it. The syntax for the close method is,

    streamObj.close();

streamObj is the object that was used in the open method. Next you have the dot as expected, then you have the close method call. This call takes no argument.

The is_open Method
When you call the open method for any of the classes, the file may not be opened if there is an error. For example, the drive may have bad sectors and the file would not be opened. You need to use the is_open method to check if the file was successfully opened. This method returns a Boolean true if the file was successfully opened, or a Boolean false, if it was not. If a file was successfully opened, then you can proceed to access the stream, after which you close the file. When you close the file, everything in the stream is saved into the disk. If the opening process was not successful, then you should not proceed to use the file. The is_open method syntax is

    streamObj.is_open();

Its object is the same object you used in the open method. It takes no argument. Of course, there is a dot between the object identifier and the method name.

The ofstream Class
The ofstream class is used basically to produce a new file. For simple cases, you do not need the mode argument to use this class. The syntax to create an object from the class, ofstream is

    ofstream fileStrm;

You begin with the class name followed by a space then the identifier (name) of the object (any name you like). I have given the name, fileStrm, above. To send a line of text to the stream you do this:

    fileStrm << "This is a line.\n";

You begin with the identifier of the object. Next you have the << operator and then the string that makes up the line. The \n character at the end of the current string, forces the next string to be “typed” in the file, to go to the next line. You repeat the above for the different lines you want. When you close the stream (fileStrm), everything you sent to the stream is saved in the physical file in disk. The following code opens a new file whose name is myfile.txt. It sends three lines to the corresponding stream, then saves the file as it closes the stream. Read and try it:

#include <fstream>
#include <iostream>
using namespace std;

    int main()
    {    
        ofstream writeStrm;
        writeStrm.open("myfile.txt");
        if (writeStrm.is_open())
            {
                writeStrm << "This is the first line.\n";
                writeStrm << "This is the second line.\n";
                writeStrm << "This is the third line.\n";
            }
        writeStrm.close();

        return 0;
    }

Note the inclusion of the fstream header (file). The three writing lines can be reduced to one as follows:

    writeStrm << "This is the first line.nThis is the second line.nThis is the third line.\n";

In the long string above, the \n character forces the next potion of the string to the next line.

A Bit about the string Class
There is a predefined class called the string class. This class is used to instantiate (create) an object that will hold a string. The syntax to create such an object is,

    string myStr;

where myStr is the identifier you give for the string object; you can give any name you want. The header file that provides this class is called, string.

Hey, you can also use the string class as object type for your array elements. The declaration of the array is something like,

    string myArray[10];

The object type for each of the array element is string. The array identifier above is myArray. The declaration above assumes that there will be 10 elements in the array. Each element in the array will be a string (phrase).

The getline Function
The string header file also has a function called the getline function whose syntax, in simple terms is:

    getline(streamObj, strObjIdent)

The first argument is the identifier of a stream object. The second is the identifier of a string object, instantiated from the string class. Now, this getline function reads a line of text from a stream and puts it in the object identified by strObjIdent. You can then display (print) the content of strObjIdent. The getline function gets the text of the line without the ending \n character.

The ifstream Class
This is basically used to read a file. For simple cases, you do not need the mode argument to use this class. The syntax to create an object from the class, ifstream is

    ifstream fileStrm;

You begin with the class name followed by a space then the identifier (name) of the object (any name). To read a line from the stream, you do this:

    getline(streamObj, strObjIdent)

I have explained this function and its argument above. The following code reads the three lines of the file created above. Read and try it.

#include <fstream>
#include <string>
#include <iostream>
using namespace std;

    int main()
    {    
        ifstream readStrm;
        string line;
        readStrm.open("myfile.txt");
        if (readStrm.is_open())
            {
                getline(readStrm, line);
                cout << line; cout << "\n";
                getline(readStrm, line);
                cout << line; cout << "\n";
                getline(readStrm, line);
                cout << line; cout << "\n";
            }
        readStrm.close();

        return 0;
    }

The \n character forces the next printed (display) line to the next line. Note the inclusion of the string header (for getline).

File Position Indicator
When a file is opened successfully, a stream for the file is established. There is what is called a file position indicator. When a file is just opened, everything being equal, this indicator points to the beginning of the file stream. Whatever you do to the stream will happen at the character or line the file position indicator is pointing to. When you read a line of text, the file position indicator would point to the next line to be read, everything being equal. When you write a line, the file position indicator would point to the end (just after) of the line just written, everything being equal.

The eof method
The eof method for end-of-file is used to detect whether the file position indicator has reached the end of the stream, which corresponds to the end of file in the disk. The return value of this method is true (of type bool) when the end of file is reached, or false when the end of file has not been reached.

The syntax to use the eof method is,

    streamObjIdent.eof()

You start with the stream object identifier, then the dot and then the method call. It takes no argument.

In the following code, lines of the text file we saved are copied into an array. The code uses the eof method, to know when to stop reading the file. The contents of the array are then displayed.

#include <fstream>
#include <string>
#include <iostream>
using namespace std;

    int main()
    {
        ifstream rdStrm;
        string lineArr[100];
        int i = 0;
        rdStrm.open("myfile.txt");
        if (rdStrm.is_open())
            {
                while (!rdStrm.eof())
                    {
                        getline(rdStrm, lineArr[i]);
                        ++i;
                    }
            }
        rdStrm.close();

        for (i=0; i<100;++i)
            {
                cout << lineArr[i];
            }

        return 0;
    }

The first line in the code includes the header, fstream. You need this to have any of the three types of file objects from the three types of file (stream) classes. The second line includes the string header. This is for the declaration of the string array. Each line from the file will be read into the array. The next line in the code includes iostream. This is for the cout object (which is already instantiated for you in C++, unknown to you).

The first line in the main function, creates a file stream object for read-only. The next line creates the array of strings of the string class. It assumes that there are not more than 100 lines in the text file. There is next the definition of a counter (i) for the different lines in the file and a for-loop to count through the array. The next line checks if the file was successfully opened. If it was, then the if-block is executed and then the file is closed.

In the if-block, there is a while loop. Inside the while loop, one line from the stream is read. After reading each line, the file position indicator points to the next line in the stream. So as the while-loop repeats, all the lines in the stream are accessed. The getline statement in the while-loop reads each line. The second statement in the while-loop increments the counter so that the next line read should be sent to the next cell of the array. The while-loop is repeated until the end-of-file is reached. Note how eof is coded (checked) in the condition of the while-loop. End-of-file means end of stream.

After the if-block, you have the for-loop. This for-loop displays the content (lines) of the array.

Try the above code and note that all the lines of the file (array) will be displayed but in one line on the monitor. This is because the getline function does not read the \n character at the end of each line in the file.

The fstream Class
The fstream class is used when you want to edit (modify) a file. With this class you can write to a file and read from it. If you are writing to a file, if it did not exist, it will be created. The syntax to create an object from the class, fstream is

    fstream fileStrm;

You begin with the class name followed by a space then the identifier (name) of the object (name of your choice). Note that the name of a header is fstream. In that header, one of the classes is fstream, having the same name as the header.

The fstream class (object) uses the mode argument in its open method. Some of the possible values for the mode argument and their meanings are as follows:

ios::in : Open for reading.
ios::out : Open for writing.
ios::app : Open to append; that is add new content at the end of an already existing file content.
ios::trunc : Open for writing, but first erase all the previous content of the file (in disk).

You use the above values without quotes. If you want to change (edit) text anywhere in the file, then you should use the following for the argument:

    ios::in | ios::out

These are the values for reading and writing, linked by the | character.

Simple Editing of Text Files
A simple way to edit a file is as follows:

Open the file with an ofstream object for read-only. Copy the contents of the file into an array. Close the file (close the stream object). Next modify the contents of the array. Open the file again, but this time, with the fstream object and the, ios::trunc argument. This argument will erase the previous content of the file. Next copy the contents of the array to the fstream stream just created. Close the stream and the array content copied including the file changes would be saved. In that way you would have modified the file. The following code illustrates this. Read and try it.

#include <fstream>
#include <string>
#include <iostream>
using namespace std;

    int main()
    {
        ifstream rdStrm;
        string lineArr[100];
        int i = 0;  //counter for line number in text.
        rdStrm.open("myfile.txt");
        if (rdStrm.is_open())
            {
                while (!rdStrm.eof())
                    {
                        getline(rdStrm, lineArr[i]);
                        ++i;
                    }
            }
        rdStrm.close();

        //change all the array elements
        lineArr[0] = "This is line A.\n";
        lineArr[1] = "This is line B.\n";
        lineArr[2] = "This is line C.\n";

        //Use fstream class to save changes
        fstream rdWriteStrm;
        rdWriteStrm.open("myfile.txt", ios::trunc);
        int j = 0;  //counter for array - the value of i should now be 2, i.e. 3-1
        rdWriteStrm.open("myfile.txt");
        if (rdWriteStrm.is_open())
            {
                for (j=0; j<=i; ++j)
                    {
                         rdWriteStrm << lineArr[j];
                    }
            }
        rdWriteStrm.close();

        return 0;
    }

In practice, this array would be your text editor or word processor page. Use your operating system to open the file, myfile.txt and note that the three lines that were there have been replaced. Since the file ended with a \n character, you may see an extra line in the file. If you do not want this extra line, then do not end your file with the \n character.

Well, we have come to the end of this tutorial.

End of Series
This is the end of the series. I hope you appreciated it. There is more to learn on C++. Just search my blog.

Chrys

Related Courses

C++ Course
Relational Database and Sybase
Windows User Interface
Computer Programmer – A Jack of all Trade – Poem

Comments

Become the Writer's Fan
Send the Writer a Message