Topics to Cover
- Opening an input file
- Opening an output file
- Reading an object from an input file
- Writing an object to an output file?
- How conversion of
cin or fin as a bool works
- The meaning of
while(cin >> i)
- Opening two files at the same time
- Asking the user for a filename and opening a file with that filename
Opening an input file: declere a variable of ifstream type
Sometimes we want to read our input from a file rather than from
standard-in. In this case, cin won't help us. However, we
can create an istream object that acts just like
cin except that it gets its character stream from a file
rather than a keyboard.
To do so, let's first create a file temp with
the input for our program.
Now, the following code shows you how to open that file:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
// Declare a variable of an istream type
// variable name: fin
ifstream fin("temp");
if (fin)
{
// Found the file, read input & do work!
}
else
{
// Couldn't find the file! Report error!
}
// ...
|
- ifstream type
When I say ifstream fin; it looks like I'm declaring an
object of type ifstream (and indeed I am!).
This type is a kind of istream. As you get into more advanced
programming, the idea of subtypes will be important. For now I'll
just say this: cin and the fin we created are both of
type istream in the same way that "square" and "trapazoid" are
both in the category "quadrilateral" - they are subtypes of the type
quadrilateral.
- opening a file in a current directory
Now, if you run this, it's only going to successfully open and read from
the file temp if temp is in the current
directory, i.e. the directory you were in when you launched the
program.
|
- failure to open a file
Conversion of ifstream object into a boolean
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!
So what happens when your program doesn't find the file it's looking
for? Well, when you create fin to read from
temp, and temp does not exist, then
fin is in a state which, when cast as a bool, is
false. Thus, if we want to improve the program above so that it prints an
error message if the file temp cannot be found, we would do
Tip: Using return 1
For a lot of small programs, you simply want to print an error and exit
your program when you can't find the given file. Otherwise, just
carry-on. We usually do this as shown below. Note that "return
1;" in main has the effect of exiting the entire program
immediately, and returning a non-zero value is the traditional way of
indicating that there was some kind of error.
ifstream fin("temp");
if (!fin)
{
cout << "File \"temp\" not found!" << endl;
return 1; // exit the program!!
}
Reading from a file: use ifstream type
Reading from a file is easy as shown below. It's pretty much the same as you
read an object with cin.
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
// Create istream object that reads from file temp
ifstream fin("temp"); // note: fin has ifstream type
if (!fin)
{
cout << "File \"temp\" not found!" << endl;
return 1; // exit the program!!
}
int n;
// ********* READING ***************
fin >> n;
// *********************************
cout << "The first number is " << n << endl;
return 0;
}
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"); // note: fin has ifstream type
if (!fin)
{
cout << "File \"temp\" 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
- With
(fin >> j), the program reads an integer into variable j.
-
(fin>> j) evaulates to fin. It is quite
strange, but it's true -- so we will surely ask about this in the exam!
Therefore, after reading an integer in the above step, the code becomes
essentially the same as while(fin)
- Since it's located in the
while condition, fin is
converted into a boolean value (i.e., the state of fin).
- If the reading failed, it will be
false.
- If the reading succeeded, it will be
true.
Think of while(fin >> j) as follows:
"while fin >> j succeeds ...".
| Original | Meaning
|
while(fin >> j) // ***
{
k = k + j;
}
|
fin >> j; // step 1
while(fin) // step 2
{
k = k + j;
fin >> j; // step 1 -- repeated
}
|
|
When a file ends
The above 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.
Writing to a file
Just as reading from a file is not much different from reading
from cin, writing to a file is not much different
from writing to cout. First, you need to create an
object of type ostream like cout, but
which sends its output to a file. To do this, you declare a
variable of type ofstream.
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
// Create ostream object that writes to file outfile
ofstream fout("outfile");
// Write 1 through 10 on separate lines
int i;
i = 1;
while(i <= 10)
{
fout << i << endl;
i = i + 1;
}
return 0;
}
You don't really have the issue of checking to see if the file is
found, since you're trying to create a new file. If there is file
of that name already there, it gets obliterated ... oops!
Reading two files at the same time
Can you read two files at the same time? Yes! Simply create two variables of
ifstream type at the same time!
ifstream fin1("in1.txt");
ifstream fin2("in2.txt");
int a1, a2;
while( (fin1 >> a1) && (fin2 >> a2) ) // while reading succeeds..
cout << "file1:" << a1 << ", file2:" << a2 << endl;
The above code will open in1.txt and in2.txt at the same time and read (and
print) an integer from each file.
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 that variable dies,
and this closes the connection to the file.
- 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.
Opening files when the user provides the filename
If name is a string object with
the name of the file you'd like to open, then
string name;
cin >> name;
ifstream fin(name);
opens an input stream to that file.
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".
Sample run:
$ echo "1 3 2 4 10 8 7 5" > data.txt
$ cat data.txt
1 3 2 4 10 8 7 5
$ ./a.out
Filename? data.txt
$ cat even.txt
2 4 10 8
$ cat odd.txt
1 3 7 5
Solution: here.
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.