cincin 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;
cin >> j
while(cin)
{
k = k + j;
cin >> 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, stopping at the ';' ... 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 "cin" is of
type istream and is cast to the bool
value true - meaning the loop continues. However,
after adding 4 to the sum we try to read
another int but encounter a ';' instead, meaning
that the read fails.
So the loop condition for the next iteration
takes cin
and casts it to the bool
value false, and the loop terminates. In fact,
in this state any subsequent attempts to read will fail. This
is a cool trick.
More often than not, we use the the fact that
the expression cin >> j is an expression that
evaluates to cin (with the side effect of reading
into the variable j), to write the above more
compactly as
int j, k;
k = 0;
while(cin >> j)
{
k = k + j;
}
cout << k << endl;
We think of this as "while cin >> j succeeds ...".
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
indeed I am!), and
yet I claimed 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, i.e. the directory you were in
when you launched the program.
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:
return 1;" in main has the effect of
exiting the 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;
}
...
// 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!
}
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;
Important Unix note: If you're entering data into the
terminal, you can send an "end of file" to the program by pressing
ctrl-d. Thus, when running something like
int count = 0;
char c;
while(cin >> c)
{
if (c == ' ')
count = count + 1;
}
you can signal the end of the input, and make the program break
out of the while loop, by pressing ctrl-d.
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.
fin
explicitly at any time with: fin.close()
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?
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
fin(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,
then
s.c_str() evaluates to the C-style version of the
same string.