cinThe now-familiar cin object has type
istream. It
is, in fact, the only object of that type we've seen up 'til now. Other than
the >> operator, we haven't used it like we've used other types - we
never try any other operations. Oddly enough, objects of type
istream can be cast as type
bool, which means for
example that they can be used in the test condition of a loop or an
if-statement. But what does that mean?!?!? Lets look at an
example:
int j, k;
k = 0;
while(cin >> j)
{
k = k + j;
}
cout << k << endl;
|
Now what does this do? Well, if I run this program and enter
1 2 3 4;
... it'll print out 10. What it's done is to compute the sum of the numbers entered ... but why?
Well, when cin (or any other object of type
istream) fails to read in an object of the type you've requested,
it goes into a state that as a bool is
false.
Otherwise, it translates into the bool
true. So, in
our loop, each time we read in a new int successfully with
cin >> j the evaluated expression (which is just
cin after the read) is of type
istream and is cast
to the bool value
true - meaning the loop continues.
However, after reading the 4, the loop condition for the next iteration has
cin trying to read the character ';' and interpret
it as an int, which it can't do. The read fails, so when we cast
to the bool value we get
false, and the loop
terminates. In fact, in this state any subsequent attempts to read will fail.
This is a cool trick.
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.
So, let's do the same program as above, but first let's create a file
temp
with the input for our program.
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
// Create istream object that reads from file temp
ifstream fin("temp");
// 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 sum of all int's read
cout << k << endl;
return 0;
}
|
A few comments:
When I say ifstream fin; it looks like I'm
declaring an object of type ifstream, and yet I claim to be
creating an object of type istream, which is it? Well ... it's
both. 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.
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. When I launch a program it has a current directory in
which it looks for files that get referenced from within the program. When you
run a program from Visual C++, its current directory defaults to the project
directory - i.e. to the directory in which your source files reside.
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 the following:
// Create istream object that reads from file temp
ifstream fin("temp");
if (fin)
{
// Found the file, read input & do work!
}
else
{
// Couldn't find the file! Report error!
}
|
When reading data from a file, we often want to simply read until a file
ends. Since there isn't really an obvious analogue to that when reading from
the keyboard, we haven't had to deal with anything like this. The idea is
this, if you try to read an object, say an
int for example, and
the file ends before istream object can read an
int,
the istream object goes into an error state again - i.e. casting
it to a bool would result in the value false. So, if you had a
file infile that simply consisted of a bunch of numbers, nothing
else, you could sum these numbers with the following code:
// Open ifstream to "infile"
ifstream fin("infile");
// Read & sum each number in file
int k, sum;
sum = 0;
fin >> k;
while (fin)
{
sum = sum + k;
fin >> k;
}
// Print out result
cout << sum << endl;
|
If you prefer, we can use some of our shortcuts, namely that
fin
>> k has the side effect of reading a new value into
k, as well as being an expression that has the value of the
object fin after the new value is read into
k.
// Open ifstream to "infile"
ifstream fin("infile");
// Read & sum each number in file
int k, sum;
sum = 0;
while (fin >> k)
sum = sum + k;
// Print out result
cout << sum << endl;
|
We know how to create an ifstream object that is open for
reading to a file. How are input file streams closed? Well, when the
ifstream object goes out of scope that variable dies, and this
closes the connection to the file. If another
ifstream object is
created to read from the same file, it starts over at the beginning.
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! A fully featured program might
warn the user of this. Can you think of how you might check whether the file
outfile already exists?
If name is a
string object with the name of the
file you'd like to open, then
ifstream fin(name.c_str());
opens an input stream to that file, not
ifstream (name), like
you'd hope. The following also works:
ifstream fin; fin.open(name.c_str());
The deal is this: the iostream stuff expects a C-style string,
not a C++ string object. when you have a C++
string
object s,
s.c_str() evaluates to the C-style version
of the same string.
Last modified LT M. Johnson: 08/15/2007 04:32 PM