A "Feild" Guide to Programming with C++
Introductory programming notes by Henry FeildChapter 9: File IO
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 ofifstream
orofstream
, pass in either a string literal or use thec_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:
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.
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:
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.
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:
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)