Tải bản đầy đủ (.pdf) (10 trang)

Absolute C++ (4th Edition) part 50 pdf

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (265.04 KB, 10 trang )

Programming Projects 497
10. The program would behave exactly the same. However, most authorities favor using the
using declaration, as we have done in Display 11.10. Note that with either, there are still
two different functions named
readHour. The one in Display 11.10 is different from the
one defined in the unnamed namespace in Display 11.9.
11.
Hello from unnamed.
Hello from Sally.
Hello from unnamed.
12. Outer.
Inner.
Inner.
PROGRAMMING PROJECTS
1. This exercise is intended to illustrate namespaces and separate compilation in your develop-
ment environment. You should use the development environment you regularly use in this
course for this exercise. In a file
f.h, place a declaration of void f( ) in namespace A. In
file
g.h, place a declaration of void g( ) in namespace A. In files f.cpp and g.cpp, place
the definitions of
void f( ) and void g( ), respectively. Place the definitions of void
f( ) and void g( ) in namespace A. The functions can do anything you want, but to
keep track of execution include something like
cout <<"
Function_Name
called" << endl;
where
Function_Name
is the name of the particular function. In another file, main.cpp, put
your


main function, #include the minimum collection of files to provide access to the
names from namespace
A. In your main function call the functions f then g. Compile,
link, and execute using your development environment. To provide access to names in
namespaces, you may use local
using declarations such as:
using std::cout;
or use local using directives such as:
using namespace std;
inside a block, or qualify names using the names of namespaces, such as std::cout. You
may not use global namespace directives such as the following which are not in a block and
apply to the entire file:
using namespace std;
Of course you must handle namespace A and function names f and g, in addition to possi-
bly
std and cout.
After doing the above, write a one page description of how to create and use namespaces
and separate compilation in your environment.
498 Separate Compilation and Namespaces
2. Obtain the source code for the PFArrayD class and the demonstration program from Dis-
plays 10.10, 10.11, and 10.10. Modify this program to use namespaces and separate com-
pilation. Put the class definition and other function declarations in one file. Place the
implementations in a separate file. Distribute the namespace definition across the two files.
Place the demonstration program in a third file. To provide access to names in namespaces,
you may use local
using declarations such as:
using std::cout;
or use local using directives such as:
using namespace std;
inside a block, or qualify names using the names of namespaces, such as std::cout. You

may not use global namespace directives such as the following which are not in a block and
apply to the entire file:
using namespace std;
3. Extend the Programming Project 1 from Chapter 10 in which you implemented a two
dimensional array class by placing the class definition and implementation in a namespace,
then providing access to the names in the namespace. Test your code. To provide access to
names in namespaces, you may use local
using declarations such as
using std::cout;
or use local using directives such as:
using namespace std;
inside a block, or qualify names using the names of namespaces, such as std::cout. You
may not use global namespace directives such as the following which are not in a block and
apply to the entire file:
using namespace std;
1.7
For additional online
Programming Projects,
click the CodeMate icons
below.

12

Streams and File I/O
12.1 I/O STREAMS 501
File I/O 501
Pitfall: Restrictions on Stream Variables 506
Appending to a File 506
Tip: Another Syntax for Opening a File 508
Tip: Check That a File Was Opened Successfully 509

Character I/O 512
Checking for the End of a File 513
12.2 TOOLS FOR STREAM I/O 517
File Names as Input 517
Formatting Output with Stream Functions 518
Manipulators 521
Saving Flag Settings 523
More Output Stream Member Functions 524
Example: Cleaning Up a File Format 525
Example: Editing a Text File 528
12.3 STREAM HIERARCHIES: A PREVIEW OF INHERITANCE 528
Inheritance among Stream Classes 528
Example: Another

newLine
Function 533
12.4 Random Access to Files 536
CHAPTER SUMMARY 538
ANSWERS TO SELF-TEST EXERCISES 539
PROGRAMMING PROJECTS 541

12

Streams and File I/O

Fish say, they have their stream and pond;
But is there anything beyond?

Rupert Brooke,


Heaven

(1913)

As a leaf is carried by a stream, whether the stream ends in a
lake or in the sea, so too is the output of your program carried by
a stream not knowing if the stream goes to the screen or to a file.

Washroom Wall of a Computer Science Department (1995)
INTRODUCTION

Input is delivered to your program and output from your program is delivered
to the output device via special objects known as

streams

. The term

stream

is
supposed to convey the idea that the output is streamed to or from your pro-
gram without your program being aware (or at least not very aware) of where
the input data came from or where the output data goes. This should, and
does, mean that file input is handled in essentially the same way as the key-
board input we have been using up to now and that file output is handled in
essentially the same way as screen output.
File I/O makes a small but essential use of inheritance, which is not covered
until Chapter 14. However, we have placed this chapter before the inheritance
chapter because programmers often want to start using file I/O early. There-

fore this chapter includes a brief introduction to what few inheritance details
are needed for file I/O.
You may cover this chapter anytime after covering the material of Chapters
1 to 4 and 6 to 9; in other words, you may cover this chapter before Chapters
5, 10, and 11. Enough material to allow you to do simple file I/O can be cov-
ered even before reading all those chapters. The basic elements of file I/O,
which are discussed in Section 12.1, may be covered anytime after reading
Chapters 1 to 4, Chapter 6, and the subsection of Chapter 9 entitled “The
Member Functions

get

and

put

.” That subsection is self-contained and does
not require reading any other parts of Chapter 9. All of Section 12.2, except
for the subsection entitled “File Names as Input”



may also be read after read-
ing only Chapters 1 to 4, Chapter 6, and the subsection of Chapter 9 entitled
“The Member Functions

get

and


put

.”
If you have not read Chapter 11 on namespaces, you may want to review
the subsection of Chapter 1 on namespaces.
I/O Streams 501

I/O Streams

Good Heavens! For more than forty years I have been speaking
prose without knowing it.

Molière,

Le Bourgeois Gentilhomme

A

stream

is a flow of characters (or other kind of data). If the flow is into your pro-
gram, the stream is called an

input stream

. If the flow is out of your program, the
stream is called an

output stream


. If the input stream flows from the keyboard, then
your program will take input from the keyboard. If the input stream flows from a file,
then your program will take its input from that file. Similarly, an output stream can go
to the screen or to a file.
Although you may not realize it, you have already been using streams in your pro-
grams. The

cin

that you have already used is an input stream connected to the key-
board, and

cout

is an output stream connected to the screen. These two streams are
automatically available to your program as long as it has both an

include

directive that
names the header file

<iostream>

and a

using

directive for the


std

namespace. You can
define other streams that come from or go to files; once you have defined them, you
can use them in your program in the same way you use the streams

cin

and

cout

. For
example, suppose your program defines a stream called

inStream

that comes from
some file. (We’ll tell you how to define it shortly.) You can then fill an

int

variable
named

theNumber

with a number from this file by using the following in your program:

int theNumber;

inStream >> theNumber;

Similarly, if your program defines an output stream named

outStream

that goes to
another file, then you can output the value of the variable

theNumber

to this other file.
The following will output the string

"theNumber is "

followed by the contents of the
variable

theNumber

to the output file that is connected to the stream

outStream

:

outStream << "theNumber is " << theNumber << endl;

Once the streams are connected to the desired files, your program can do file I/O the

same way it does I/O using the keyboard and screen.


FILE I/O

The files we will use for I/O in this chapter are text files; that is, they are the same kind
of files as those that contain your C++ programs.
When your program takes input from a file, it is said to be

reading

from the file;
when your program sends output to a file, it is said to be

writing

to the file. There are
other ways of reading input from a file, but the method given in this subsection reads
the file from the beginning to the end (or as far as the program gets before ending).
12.1
stream
input
stream
output
stream
cin and
cout are
streams
reading
and

writing
502 Streams and File I/O

Using this method, your program is not allowed to back up and read anything in the
file a second time. This is exactly what happens when your program takes input from
the keyboard, so it should not seem new or strange. (As we will see, your program can
reread a file starting from the beginning of the file, but this is starting over, not backing
up.) Similarly, for the method presented here, your program writes output into a file
starting at the beginning of the file and proceeding forward. Your program is not
allowed to back up and change any output that it has previously written to the file. This
is exactly what happens when your program sends output to the screen: You can send
more output to the screen, but you cannot back up and change the screen output. The
way that you get input from a file into your program or send output from your pro-
gram into a file is to connect your program to the file by means of a stream.
To send output to a file, your program must first connect the file to a (stream) object
of the class

ofstream

. To read input from a file, your program must first connect the
file to a (stream) object of the class

ifstream

. The classes

ifstream

and


ofstream

are
defined in the

<fstream>

library and placed in the

std

namespace. Thus, to do both file
input and file output, your program would contain

#include <fstream>
using namespace std;

or

#include <fstream>
using std::ifstream;
using std::ofstream;

A stream must be declared just as you would declare any other class variable. Thus,
you can declare

inStream

to be an input stream for a file and


outStream

to be an out-
put stream for another file as follows:

ifstream inStream;
ofstream outStream;

Stream variables, such as

inStream

and

outStream

declared above, must each be
connected to a file. This is called

opening the file

and is done with the member func-
tion named

open

. For example, suppose you want the input stream

inStream


con-
nected to the file named

infile.txt

. Your program must then contain the following
before it reads any input from this file:

inStream.open("infile.txt");

You can specify a pathname (a directory or folder) when giving the file name. The
details of how to specify a pathname vary a little from system to system, so consult with
a local guru for the details (or do a little trial-and-error programming). In our examples
we will use simple file names, which assumes that the file is in the same directory
(folder) as the one in which your program is running.
<fstream>
declaring
streams
connecting a
stream to a file
open
pathnames
I/O Streams 503

Once you have declared an input stream variable and connected it to a file using the

open

function, your program can take input from the file using the extraction operator,


>>

, with the input stream variable used the same way as

cin

. For example, the following
reads two input numbers from the file connected to

inStream and places them in the
variables
oneNumber and anotherNumber:
int oneNumber, anotherNumber;
inStream >> oneNumber >> anotherNumber;
An output stream is opened (that is, connected to a file) in the same way as just
described for input streams. For example, the following declares the output stream
out-
Stream
and connects it to the file named outfile.txt:
ofstream outStream;
outStream.open("outfile.txt");
When used with a stream of type ofstream, the member function open will create the
output file if it does not already exist. If the output file already exists, the member func-
tion
open will discard the contents of the file so that the output file is empty after the
call to
open. (We will discuss other ways of opening a file a bit later in this chapter.)
After a file is connected to the stream
outStream with a call to open, the program
can send output to that file using the insertion operator

<<. For example, the following
writes two strings and the contents of the variables
oneNumber and anotherNumber to
the file that is connected to the stream
outStream (which in this example is the file
named
outfile.txt):
outStream << "oneNumber = " << oneNumber
<< " anotherNumber = " << anotherNumber;
Notice that when your program is dealing with a file, it is as if the file had two
names. One is the usual name for the file that is used by the operating system, which is
the external file name. In our sample code the external file names were
infile.txt
and outfile.txt. The external file name is in some sense the “real name” for the file.
The conventions for spelling these external file names vary from one system to another.
The names
infile.txt and outfile.txt that we used in our examples may or may not
look like file names on your system. You should name your files following whatever
O
VERLOADING

OF

>>

AND

<<
A
PPLIES


TO
F
ILES
As we pointed out in Chapter 8, if you overload >> and <<, then those overloadings apply to file
input and output streams the same as they apply to
cin and cout. (If you have not yet read
Chapter 8, you can ignore this remark. It will be repeated for you in Chapter 8.)
external file
name
504 Streams and File I/O
conventions are used on your operating system. Although the external file name is the
real name for the file, it is typically used only once in a program. The external file name
is given as an argument to the function
open, but after the file is opened, the file is
always referred to by naming the stream that is connected to the file. Thus, within your
program, the stream name serves as a second name for the file.
The sample program in Display 12.1 reads three numbers from one file and writes
their sum, as well as some text, to another file.
Every file should be closed when your program is finished getting input from the
file or sending output to the file. Closing a file disconnects the stream from the file. A
file is closed with a call to the function
close. The following lines from the program in
Display 12.1 illustrate how to use the function
close:
inStream.close( );
outStream.close(
);
Notice that the function close takes no arguments. If your program ends normally but
without closing a file, the system will automatically close the file for you. However, it is

good to get in the habit of closing files for at least two reasons. First, the system will
only close files for you if your program ends normally. If your program ends abnor-
mally due to an error, the file will not be closed and may be left in a corrupted state. If
your program closes files as soon as it is finished with them, file corruption is less likely.
Second, you may want your program to send output to a file and later read that output
back into the program. To do this, your program should close the file after it is finished
writing to the file, and then reopen the file with an input stream. (It is possible to open
a file for both input and output, but this is done in a slightly different way.)
A less commonly used member function, but one you may eventually need, is
flush, which is a member function of every output stream. For reasons of efficiency,
output is often buffered—that is, temporarily stored someplace—before it is actually
written to a file. The member function
flush flushes the output stream so that all out-
put that may have been buffered is physically written to the file. An invocation of
close automatically invokes flush, so you very seldom need to use flush. The syntax
for flush is indicated by the following example:
outStream.flush( );
A F
ILE
H
AS
T
WO
N
AMES
Every input and every output file used by your program has two names. The external file name is
the real name of the file, but it is used only in the call to the member function
open, which con-
nects the file to a stream. After the call to
open, you always use the stream name as the name of

the file.
close
I/O Streams 505
Display 12.1 Simple File Input/Output
1 //Reads three numbers from the file infile.txt, sums the numbers,
2 //and writes the sum to the file outfile.txt.
3 #include <fstream>
4 using std::ifstream;
5 using std::ofstream;
6 using std::endl;
7 int main(
)
8 {
9 ifstream inStream;
10 ofstream outStream;
11 inStream.open("infile.txt");
12 outStream.open("outfile.txt");
13 int first, second, third;
14 inStream >> first >> second >> third;
15 outStream << "The sum of the first 3\n"
16 << "numbers in infile.txt\n"
17 << "is " << (first + second + third)
18 << endl;
19 inStream.close(
);
20 outStream.close(
);
21 return 0;
22 }
S

AMPLE
D
IALOGUE
There is no output to the screen
and no input from the keyboard.
infile.txt
(Not changed by program)
1
2
3
4
outfile.txt
(After program is run)
The sum of the first 3
numbers in infile.txt
is 6
A better version of this program is
given in Display 12.3.
506 Streams and File I/O
Pitfall
R
ESTRICTIONS

ON
S
TREAM
V
ARIABLES
You declare a stream variable (one of type ifstream or ofstream) in the usual way, but these
variables cannot be used in some of the ways that other variables are used. You cannot use an

assignment statement to assign a value to a stream variable. You can have a parameter of a
stream type (
ifstream, ofstream, or any other stream type), but it must be a call-by-
reference parameter. It cannot be a call-by-value parameter.

APPENDING TO A FILE
When sending output to a file, your code must first use the member function open to
open a file and connect it to a stream of type
ofstream. The way we have done this thus
far (with a single argument for the file name) always yields an empty file. If a file of the
specified name already exists, its old contents are lost. There is an alternative way to
open a file so that the output from your program will be appended to the file after any
data already in the file.
To append your output to a file named
"important.txt", you would use a two-
argument version of
open, as illustrated by the following:
ofstream outStream;
outStream.open("important.txt", ios::app);
If the file "important.txt" does not exist, this will create an empty file with that name
to receive your program’s output; if the file already exists, then all the output from your
program will be appended to the end of the file, so that old data in the file is not lost.
This is illustrated in Display 12.2.
The second argument
ios::app is a defined constant in the class ios. The class ios
is defined in the <iostream> library (and also in some other stream libraries). The defi-
nition of the class
ios is placed in the std namespace, so either of the following will
make
ios (and hence ios::app) available to your program:

#include <iostream>
using namespace std;
or
#include <iostream>
using std::ios;
ios::app

×