Topics to Cover
- Initializing a variable in variable declaration.
- <fstream> library
- Writing/reading to/from a file
- Closing files. Letting the user provide a filename. Opening two files at once.
- Checking failures.
- The meaning of
while(fin >> i)
Shortcut: Initializing variables in the declaration
Up 'til now, we've usually made delcaring a variable and
initializing that variable (i.e. giving the variable
it's initial value in the program) separate steps. However, in
C++ you may give a variable it's initial value at the same time
you declare it by simply putting "= value" or
(value) after
the variable's name in the declaration.
For example, the following code declares variables x and
y and gives an inital value of 1.0 and
200 to them respectively.
double x = 1.0, y(200);
Including the Necessary Library
To work with files in C++, we need to include the fstream library:
#include <fstream>
This library provides two important types:
-
ifstream: for reading from files (input stream)
-
ofstream: for writing to files (output stream)
Writing To a file
Opening an Output File
To open a file for writing, declare an ofstream variable and pass the filename
as a string:
ofstream fout("out.txt");
-
ofstream is a type (just like int or
double).
-
fout is the variable name (you can choose any valid name).
- "out.txt" is the name of the file you want to open.
Important:
- If the file already exists, its contents will be overwritten.
- If it does not exist, the file will be created.
Writing to a file
- To write to the terminal, you can send objects
to the
ostream variable
cout.
- To write to the file, you can send objects to
the
ofstream variable you
declared.
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
// Again, fout is a variable, and ostream is a type
ofstream fout("out.txt");
int i;
i = 1;
while(i <= 10)
{
fout << i << endl; // fout: write i into the file
i = i + 1;
}
return 0;
}
|
Note: Do not confuse cout and fout.
-
cout prints to screen.
-
fout writes into the file.
|
Reading From a File
Opening an Input File
To open a file for reading, declare an ifstream variable and pass the filename
as a string:
ifstream fin("temp.txt");
-
ifstream is a type (just like int or
double).
-
fin is the variable name (you can choose any valid name).
- "temp.txt" is the name of the file you want to open.
Important: The file must exist in the current working directory
(the directory where you run your program).
Reading data
Reading from a file is very similar to reading input with cin.
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ifstream fin("temp.txt");
int n;
// ********* READING ***************
fin >> n;
// *********************************
cout << "The first number is " << n << endl;
return 0;
}
|
Note: The code fin >> n extracts an integer from the file
temp.txt into variable n.
|
Other Useful Things
Closing input file streams
We know how to create an ifstream object that is open for
reading to a file. How are input file streams closed?
- When the
ifstream object goes out of scope, it is automatically
closed.
- You can close a filestream named
fin
explicitly at any time as follows:
fin.close()
When you close a file, and a new ifstream variable is created to
read from the same file, it starts over at the beginning.
Letting the User Provide a Filename
Often, we don't know in advance which file to open. Instead, we let the user
specify the filename at runtime:
string name;
cin >> name; // user types filename
ifstream fin(name); // open that file
Working with Two Files at Once
Can you read two files? Yes! Simply create two variables of
ifstream type at the same time!
ifstream fin1("in1.txt");
ifstream fin2("in2.txt");
int a1, a2;
fin1 >> a1;
fin2 >> a2;
cout << "file1:" << a1 << endl;
cout << "file2:" << a2 << endl;
-
fin1 >> a1 reads the next integer from the first file.
-
fin2 >> a2 reads the next integer from the second file.
Important: Checking Failures
File open failure
If the file cannot be opened (for example, if it does not exist), the stream
will enter a failure state. You can check this by converting the stream into a
bool.
ifstream fin("temp.txt");
// if fin enters a failure state
if (!fin)
{
cout << "File not found!" << endl;
return 1; // exit the program!!
}
|
Conversion of ifstream object into a bool
The boolean value represents the state of fin. In particular,
-
true, when fin is in a good state.
-
false, when it's in a failure state.
Note: The same idea applies to cin and cout too!
|
Using return 1
-
return exits the entire program immediately.
- Returning a non-zero value is the traditional way of indicating an error.
Reading failure
Likewise, you can check whether the reading operation has failed by later
checking the state of fin.
string fname;
cin >> fname;
ifstream fin(fname);
int k;
fin >> k;
if( fin )
{
// fin is still in good state
cout << "k was " << k << endl;
}
else
{
// fin has gone bad
cout << "reading failed!" << endl;
}
|
Try:
- test1.txt which contains: 2 3 7
- test2.txt which contains: hello world
- test3.txt which contains nothing
|
Summing all the numbers in the file
Now, let's write code that sums all the numbers in file temp
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
// Create istream object that reads from file temp
ifstream fin("temp.txt"); // note: fin has ifstream type
if (!fin)
{
cout << "File not found!" << endl;
return 1; // exit the program!!
}
// Loop and add as long as more int's can be read
int j, k;
k=0;
while(fin >> j)
{
k = k + j;
}
// Print out the sum k
cout << k << endl;
return 0;
}
|
|
How while(fin >> j) works
- Step 1: With
(fin >> j), the program reads an integer into variable j.
- Step 2:
(fin>> j) evaluates to
fin.
- Step 3: Since
fin is located in the while condition, fin is
converted into a boolean value (i.e., the state of fin).
- If the reading fails, the condition is
false.
- If it succeeds, it is
true.
When a file ends:
The code will keep reading an integer, and it will eventually read all the
integers in the file. Then, reading will fail and the loop will stop.
|
Mandatory Practice Problem
Simple data bucketing.
Write a program that works as follows:
- Ask the user for a filename containing integers.
- Store the even numbers in the file in file "even.txt" and the odd numbers in "odd.txt".
Solution: here.
|
|
Download data.txt.
Sample run:
$ ./a.out
Filename? data.txt
$ cat data.txt
1 3 2 4 10 8 7 5
$ cat even.txt
2 4 10 8
$ cat odd.txt
1 3 7 5
|
Other Practice Problems
-
A simple data-conversion problem. You'd be amazed how often
you need to write programs that do nothing more than convert
data from one format to another.
Write a program that reads in a file (name given by user)
that contains points in ordered pair notation, and writes the
same points to a file (name also given by user) in gnuplot
notation, i.e. one point per line, each point given by
x-coordinate tab ('\t') y-coordinate.
For a nice small file to test with, we have
testin.txt. For a nice big challenge
file, we have in.txt.
a solution.