Transcript Document

File I/O
ifstreams and ofstreams
Sections 11.1 & 11.2
1
Introduction
Up to now we have been:
• getting input from the keyboard via cin
•
sending output to the screen via cout
and cerr
We now see how to:
• get input from a text file
•
send output to a text file
2
Problem
Using OCD, design and implement
a program that computes the
average of a sequence of numbers
stored in a file.
data1.txt
80
97 93.5
72
65.8
.
.
.
68.3
Project 9
3
Preliminary Analysis
Using #include <iostream>, a
program can read from the keyboard
via the istream named cin,
but this is of little benefit when the
data we need is in a file.
What we need is a way to somehow
establish an istream-like connection
between our program and the
input file, such that we can
then read from the file via that connection.
Program
data1.txt
80
97 93.5
72
65.8
.
.
.
68.3
4
Behavior
Our program should display its purpose
and then display a prompt for the name
of the input file, which it should then read.
Our program should open a connection
from itself to that input file. It should
then read the numbers from the input
file via the connection, and compute
their sum and count. It should then
close the connection, and compute and
display the average of the numbers.
Program
data1.txt
80
97 93.5
72
65.8
.
.
.
68.3
5
Objects
Description
Type
Kind
Name
purpose, prompt
string
constant
(none)
file name
string
varying
inFileName
connection
??
varying
fin
a number
double
varying
number
sum
double
varying
sum
count
double
varying
count
average
double
varying
average
6
Operations
Description
Library?
Name
display a string
read a string
open a connection
to a file
read numbers via
connection
sum & count numbers
close connection
compute average
display average
string
string
<<
getline()
??
??
??
??
built-in
??
built-in
iostream
or >> if no
blanks in
filenames
+=, ++, loop
??
/
<<
7
Algorithm
and prompt for input file name.
0. Display
Displaypurpose
purposeofofprogram,
program
1. Read name of input file from cin into inFileName.
2. Open connection named fin to file named in inFileName.
3. Initialize sum, count to zero.
4. Loop:
a. Try to
fincin
intointo
number.
to read
readaavalue
valuefrom
from
number.
b. If
left, terminate
If no
no values
valueswere
are left,
terminaterepetition.
repetition.
c. Add number to sum.
d. Increment count.
End loop.
5. Close fin.
6. If count > 0
a. Compute average = sum / count.
b. Display count and average with appropriate labels
Else
display error message.
8
Implementation in C++
To establish connections to an file, the
<fstream> library provides file-stream types:
• the ifstream class for input streams
• the ofstream class for output streams
The programmer uses these types to declare
file-stream objects; for example,
ifstream fin;
ofstream fout;
9
To connect such fstream objects to files:
Method 1: Use the open() function member in
these classes:
ifstream fin;
fin.open("name of file");
ofstream fout;
fout.open("name of file");
Method 2: Use initializing declarations:
ifstream fin("name of file");
ofstream fout("name of file");
10
Disadvantage of "hard-wiring" actual file names into a
program: the program must be modified when using a
different file.
A better alternative: Have user enter the file name and
store it in a string variable; for example,
string inFileName;
cout << "Enter name of file: ";
getline(cin, inFileName);
or use >> if
no blanks in
filenames
When attaching an fstream to this file, we must use
string's data() (or c_str()) function member
to extract the actual file name stored in the string
object; for example,
ifstream fin(infileName.data());
Similar declarations are used for output streams.
11
How to read from / write to a file connected to an
fstream:
Input: Use >> just like from an istream;
fin >> var;
or
getline()
Output: Use << just like from an ostream;
fout << expr;
Note: For output, we can use any of the
format manipulators such as endl, fixed,
setprecison(), and setw()
ifstream inherits everything from istream
ofstream
"
"
" ostream
12
When we are finished with a file — both for
input and output files — we should break the
connection between it and the program.
Although this will happen automatically when the
connection reaches the end of its scope, it is a
good idea to do this explicitly with the fstream's
function member close(); for example,
fin.close();
fout.close();
13
Objects
Description
Type
Kind
Name
purpose, prompt
string
constant
(none)
file name
string
varying
inFileName
connection
ifstream
varying
fin
a number
double
varying
number
sum
double
varying
sum
count
double
varying
count
average
double
varying
average
14
Operations
Description
Library
Name
display a string
read a string
open a connection
to a file
string
string
fstream
read numbers via
connection
sum & count numbers
close connection
compute average
display average
fstream
<<
getline()
declaration
of fstream
(or open())
>>
built-in
fstream
built-in
iostream
+=, ++, loop
close()
/
<<
or
>>
15
Two More Problems:
1. Opening a file for input can fail.
Solution: Use the ifstream function
member is_open().
In Visual C++:
create the file in
Visual C++ and
"Add to" project.
Must be in same
folder as
program.cpp
and the .vcproj
put in Resources
folder
ifstream fin(infileName.data());
assert(fin.is_open());
2. How do we know when all the data in the file
has been read?
The ifstream function member eof()
returns true if an attempted read
found no data remaining in the file.
Must try
to read
and fail
16
Coding
/*------------------------------------------------------------Program to read data values from a text file, count them,
and find their average.
Input(keyboard): Name of the file
Input(file): doubles
Note
Output(screen): Prompts, average of the data value with
labels, or file-empty message
-------------------------------------------------------------*/
#include <iostream>
// cin, cout, ...
#include <fstream>
// ifstream, ofstream, ...
#include <string>
// string
#include <cassert>
// assert()
using namespace std;
int main()
{
cout << "\nTo average the numbers in an input file,"
<< "\nenter the name of the file: ";
string inFileName;
getline(cin, inFileName);
17
OR: ifstream fin;
fin.open( infileName.data() );
ifstream fin( inFileName .data() ); // open the connection
assert(fin.is_open());
// verify it opened
double number, sum = 0.0;
int count = 0;
// variables for
// computing average
for (;;)
{
cin
>> number;
fin
_______________
// input loop
//
read number
(number
== -999)
break;
break;
if (fin.eof())
__________
//
if none were left, quit
sum += number;
count++;
}
// add it to sum
// bump up count
// end loop
fin.close();
// close fstream
18
if (count > 0)
{
double average = sum / count;
cout << "\nThe average of the values in "
<< inFileName << " is " << average << endl;
}
else
cout << "\n*** No values found in file "
<< inFileName << endl;
}
19
Testing
To test our program, we use a text editor and
create some easy-to-check input files such as
10 20
30
40
Create text
files in
Visual C++
If we name this particular file test1.txt and
enter its name when prompted by our
program, the average value produced should
be 25.
20
To average the numbers in an input file,
enter the name of the file: test1.txt
The average of the values in test1.txt is 25
Continue testing using other input files, trying to find
places where our program breaks down.
And it is is important to try various kinds of files —
ascending order, descending order, random order,
files with 1 element, empty files . . . — because
programs that work for some of these may fail for
others.
E.G.,
Project 9
21
Once we are confident that our program is
correct, we can execute it with the data file
from our problem:
data1.txt
80
97 93.5
72
65.8
.
.
.
68.3
To average the numbers in an input file,
enter the name of the file: data1.txt
The average of the values in test1.txt is 80.1
22
Key Things to Remember
The fstream library defines two classes:
ifstream, for creating connections between
programs and input files; and
ofstream, for creating connections between
programs and output files.
Both ifstream and ofstream objects are created
in a similar fashion.
23
If inFileName contains the name of an input file,
and outFileName contains the name of an output
file, then the statements
ifstream fin(inFileName.data());
or: ifstream fin;
fin.open(inFileName.data());
ofstream fout(outFileName.data());
or: ofstream fout;
fout.open(outFileName.data());
define fin and fout as connections to them.
Note that the string function member data() (or
c_str()) must be used to retrieve the actual characters of the file’s name from the file stream object.
24
If a program tries to open an ifstream to a file
that doesn’t exist, the open is said to fail.
To check whether or not an ifstream is open, the
ifstream class provides the is_open() function
member, which returns true if the ifstream was
successfully opened, and false if it not.
Whether or not a file opened correctly should
always be verified using is_open().
assert(fin.is_open());
or
assert(!fin.fail());
or use an if
25
Important Notes About Output Files:
If a program tries to open an ofstream to a file that
doesn’t exist or that can't be found, the open operation
creates a new empty file for output.
If a program tries to open an ofstream to a
file that does exist, the open operation (by default)
empties that file of its contents, creating a
Destroys it!
clean file for output.
To open an existing file for output without
emptying it, the value ios::app can be
given as a second argument:
Be careful!
ofstream fout(outFileName.data(), ios::app);
Output will be appended to whatever is already
in the file.
26
For rare occasions where a file is needed for both
input and output, the fstream class is provided:
fstream fInOut(ioFileName.data(),
ios::in | ios::out);
This statement defines an fstream named fInOut
to a file, from which data can be read, and to which
data can be written.
The bitwise OR operator (|) is used to combine file
open-modes in this manner.
27
Summary
 #include <fstream> to use file streams.
To establish a connection to a file whose name is given
by a string variable fileName:
• For input:
or:
ifstream fin(fileName.data());
ifstream fin;
fin.open(fileName.data())
• For output: ofstream fout(fileName.data());
or:
ofstream fout;
fout.open(fileName.data())
Note: data() (or c_str()) must be
used to retrieve the actual characters
of the file’s name from fileName.
28
 To check whether or not an ifstream is open:
assert(fin.is_open());
or
assert(!fin.fail());
(or use an if statement)
 Once an ifstream (or ofstream) has been opened, it
can be read from (or written to) using the usual input
(or output) operations:
input: >>, get(), getline(), ...
output: <<, put(), ...
In general, anything that can be done to an istream
(or ostream) can be done to an ifstream (or ofstream).
29
 The eof() function member provides a convenient
way to build input loops:
for (;;)
{
fin >> someValue;
if (fin.eof()) break;
// ... process someValue
}
Remember that opening a file for output erases
any contents in the file.
30
 Once we are done using an ifstream (or ofstream), it
should be closed using the close() function member:
fin.close();
fout.close();
Most systems limit the number of files a program
can have open simultaneously, so it is a good
practice to close a stream when finished with it.
 A closed file can be (re)opened using open():
fin.open(inFileName.data());
fout.open(outFileName.data());
31