Important takeaways

  • include fstream at the top of your program if reading from or writing to files
  • use the ifstream (input file stream) class for reading from files
  • use the ofstream (output file stream) class for writing to files
  • when using the open() method of an instance of ifstream or ofstream, pass in either a string literal or use the c_str() method on a string instance to convert it to a C-string; e.g.:
    • fileIn.open("myfile.txt");
    • fileIn.open(filename.c_str());
  • always close any open files before the end of your program, otherwise changes may not be saved to the file

Contents

Introduction

Up to this point, we have only made programs that interact with data provided interactively by a user. We ask the user for a number, then read the number in. Or we ask the user for a string, and then we read it in. Many times, it's useful to interact with a file, like a database or saved data. For instance, every time you open a Word document or PowerPoint slide show, Microsoft Office is reading data in from the file you specified. When you save, it's writing to a file.

In this course, we will specifically consider reading from and writing to plain text files, by which I mean that they are not in a special format (like a .docx or .pdf). This chapter will demonstrate how to read in plain text files as well as how to write text out to files.

(Back to top)

Reading files

To read a file, we need to include the fstream library (read that as: file stream). In our code (e.g., in main or some other function), we create a variable of type ifstream (read that as: input file stream). ifstream is a class with two constructors useful to us: a default constructor and an initializer constructor that take the name of the file to open. If we use the default constructor (as we do in the example below), we have to invoke the open() method to open the file. We can then read from the file and close it once we're finished. Closing the file is important! Always make sure you do it as soon as your program is done with a file. Here is a program that asks a user to enter a file name, then prints out the first word in that file on its own line:

readFile.cpp

A few things to notice. First, to open and close our file, we must invoke methods on our ifstream instance. Second, when we open a file, we need to pass not a regular string, but a C-styled string (as in the C that came before C++). We stored fileName as a string, so to convert it, we just need to invoke the method c_str() on our string instance, in this case, fileName.c_str(). Finally, reading from a file looks a lot like reading from cin: fileIn >> currentWord.

Here's a text file we can use to test this. Open up Atom or another text editor and copy/paste this text. Then save the file in the same directory as the C++ program from above, giving it the name test.txt.

test.txt
This is an example of a text file with nothing useful in it.

Here's the output:

$ ./readFile
Please enter the name of a file to print: test.txt
This

If we want to read out the entire file and not just the first word, we need to keep reading the next word from the file until nothing more can be read. We can perform this check by putting the read line inside a while condition:

If we want to read every word in the file and print it out to the terminal on its own line, our program will look like this:

readWholeFile.cpp

And here's the output of this version of the code.

$ ./readWholeFile
Please enter the name of a file to print: test.txt
This
is
an
example
of
a
text
file
with
nothing
useful
in
it.

To read entire lines of a file, we use getline(), just like we did with cin. We will make use of one of the ifstream instance methods called good(). This returns true if the file still has data to read and no errors have been encountered. So as long as good() returns true, we can keep reading a file. Here is an example program that shows off using this method in order to read every line of a file:

Sometimes it's useful to read in every character of the input file, including whitespace like spaces, tabs, and new lines. In that case, we don't want to use the >> operator since that skips whitespace. Instead, we need to use the get() method of our ifstream instance. This method reads in the next character, whatever it is, and returns it. Here's the loop we would use in place of the while in our code above to display each character of the file to the terminal:

To find out more about ifstream and how to use it, check out this reference page.

(Back to top)

Writing files

Writing files is easier than reading them! We need to include the same library we included to read files: fstream. In our program, we need to make an instance of the type ofstream (read: output file stream). Like with reading, we have begin by to opening our file and end by closing; we write in between. When a file is opened for writing, it is created if it doesn't already exist, and truncated (the contents removed) if it does exist. Unsurprisingly, ofstream behaves very similarly to cout. Here's an example of a program that writes the message "Hello from C++!" to a file specified by the user:

writeFile.cpp

Here's what it looks like when we run it:

$ ./writeFile 
Please enter the name of a file to write to: hello.txt

Now we should see that a file hello.txt has been created. Go ahead and open it with Sublime or another text editor. You should see the following text:

Hello from C++!
(Back to top)

Advanced File IO

There are many advanced features of file IO, such as appending to an existing file. I won't cover these, but I encourage you to take a look at this helpful overview of C++ file IO for more information.

(Back to top)