!!!Chapter 8 The IO Library

8.1 An Object-Oriented Library

To support or using different kinds of devices and different sized character streams, the library usesinheritance to define a set of object-oriented classes.

When one class inherits from another, we can use the same operations on both classes.

In C++ we speak of the parent as the base class and the inheriting class as a derived class.

The IO types are defined in three separate headers:

1. iostream defines the types used to read and write to a console window

2. fstream defines the types used to read and write named files

3. sstream defines the types used to read and write in-memory strings.

When we have a function that takes a reference to a base-class type, we can pass an object of a derived type to that function.

IO Library Types and Headers
HeaderTypeInternational Char
iostreamistream, ostream, iostreamwistream, wostream, wiostream
fstreamifstream, ofstream, fstreamwifstream...
sstreamistringstream, ostringstream, stringstream...

International Character Support

The library defines a corresponding set of types supporting the wchar_t type. Each class is distinguished from its char counterpart by a "w" prefix. So wostream, wistream, and wiostream read and write wchar_t data to or from a console window. 

The library also defines objects to read and write wide characters from the standard input and standard output. These objects are distinguished from the char counterparts by a "w" prefix:The wchar_t standard input object is named wcin; standard ouput is wcout; and standard error is wcerr.

Each of the IO headers defines both the char and wchar_t classes and standard input/output objects. The stream-based wchar_t classes and objects are defined iniostream, the wide character file stream types infstream, and the wide character stringstreams in sstream.

No Copy or Assign for IO Objects

The library types do not allow copy or assignment:

ofstream out1, out2;
out1 = out2;               //error: cannot assign stream objects
// print function: parameter is copied
ofstream print(ofstream);
out2 = print(out2);        //error: cannot copy stream objects

This requirement has two implications:

1. we cannot have a vector(or other container) that holds stream objects, as only element types that support copy can be stored in vectors or other container types.

2. we cannot have a parameter or return type that is one of the stream types. If we need to pass or return IO object, it must be reference or pointer.

ofstream &print(ofstream &);     //ok: takes a reference, no copy
while (print(out2)) {...}        //ok: pass reference to out2

Typically, we pass a stream as a nonconst reference because we need to read or write to the object. And reading or writing an IO object changes its state.

8.2 Condition States

The IO library manages a set of condition state members that indicate whether a given IO object is in a usable state or has encountered a particular kind of error.

The easiest way to test whether a stream is okay is to test its truth value:

if (cin)               //ok to use cin, it is in a valid state
while (cin >> word)    //ok: read operation successful

IO Library Condition State P 288

Condition States

1. strm::iostate

Each stream object contains a condition state member that is managed through the setstate and clear operations.

2. strm::badbit, strm::failbit, strm::eofbit

The badbit indicates a system level failure, such as an unrecoverable read or write error. The failbit is set after a recoverable error, such as reading a char when numeric data was expected. The eofbit is set when an end-of-file is encountered. Hitting eof also sets the failbit.

3. s.eof(), s.fail(), s.bad(), s.good()

The state of the stream is revealed by the bad, fail, eof, and good operations. If any of the first three are true, then testing the stream itself will indicate that the stream is in an error state.

4. s.clear(), s.clear(flag), s.setstate(flag)

The clear and setstate operations change the state of the condition member. The clear put the condition back in its valid state.

5. s.rdstate()

rdstate member function returns an iostate value that corresponds to the entire current condition state of the stream:

//remember current state of cin
istream::iostate old_state = cin.rdstate();
cin.clear();
process_input();            //use cin
cin.setstate(old_state);    //now reset cin to old state

Interrogating and Controlling the State of a Stream

int val;
// read cin and test only for EOF; loop is executed even if there are other IO failures
while (cin >> ival, !cin.eof())
{
    if (cin.bad())                      //input stream is corrupted; bail out
        throw runtime_error("IO stream corrupted");
    if (cin.fail())                     //bad input              
    {
        cerr << "bad data, try again";  //warn user
        cin.clear(istream::failbit);    //reset the stream
        continue;                       //get next input
    }
}

Dealing with Multiple States
When we need to set or clear multiple state bits. We can do so by making multiple calls to the setstateand clear functions. We can also use bitwise OR to do this(because different error type use different bit):

//sets both the badbit and the failbit
is.setstate (ifstream::badbit | ifstream::failbit);

It will turn on badbit and failbit, all other bits are zero.

8.3 Managing the Output Buffer

Each IO object manages a buffer, which is used to hold the data that the program reads and writes.

There are several conditions that cause the buffer to be flushed - that is, written - to the actual device or file:

1. The program completes normally. All output buffers are emptied as part of the return from main.

2. At some indeterminate time,the buffer can become full, in which case it will be flushed before writing the next value.

3. We can flush the buffer explicitly using a manipulator such as endl.

4. We can use the unitbuf manipulator to set the stream's internal state to empty the buffer after each output operation.

5. We can tie the output stream to an input stream, in which case the output buffer is flushed whenever the associated input stream is read.

Flushing the Output Buffer:

There are three normally used manipulations that can flush buffer: flush, ends, endl

cout<< "hi" << flush;   //flushes the buffer; adds no data

cout<< "hi" << ends;    //insert a null, then flushes the buffer

cout<< "hi" << endl;    //insert a newline, then flushes the buffer

The unitbuf Manipulator

If we want to flush every output, it is better to use the unitbuf manipulator:

cout<< unitbuf << "first" << "second"<< nounitbuf;

//equalsto

cout<< "first" << flush << "second" <<flush;

The nounitbuf manipulator restores the stream to use normal, system-managed buffer flushing.

Tying Input and OutputSteams Together

When an input stream is tied to an output stream, any attempt to read the input stream will first flush the buffer associated output stream.

Interface systems usually should be sure that their input and output streams are tied, so that any output, which might include prompts to the user, has been written before attempting to read.

The tie function takes a pointer to an ostream and ties the argument stream to the object on which tie was called:

//illustrationonly: the library ties cin and cout for us
cin.tie(&cout);
cin.tie(0);      //break tie between cin and cout
cin.tie(&cerr);

An ostream object can be tied to only one istream object at a time. To break an existing tie, we pass in an argument of 0.

8.4 File Input and Output

The fstream header defines three types to support file I/O:

1. ifstream, derived fromistream, reads from a file

2. ofstream, derived fromostream, writes to a file

3. fstream, derived from iostream, reads and writes the same file

In addition to the behavior that fstream types inherit from iostream, they also define two new operations:open and close. These operations can be called on objects of fstream, ifstream or ofstream but not on other IO types.

8.4.1 Using File Stream Objects

When we want to read or write a file, we must define our own objects and bind them to the desired files. Supplying a file name as an initializer to an ifstream or ofstream object has the effect of opening the specified file:

//construct an ifstream and bind it to the file named ifile
ifstream infile(ifile.c_str());
//ofstream output file object to write file named ofile
ofstream outfile(ofile.c_str());

PS: the IO library uses C-style character strings. Assuming the name of the file we wish to use is in a string, we can use c_str member to obtain C-style string. P 139

We can also define an IO object and bind it to a file later. We bind an existing fstream object to the specified file by calling the open member.

ifstream infile;      //unbound input file stream
ofstream outfile;     //unbound output file stream
infile.open("in");    //open file named "in" in the current directory
outfile.open("out");  //open file named "out" in the current directory

Checking Whether an Open Succeeded

if (!infile)
{
  cerr << "error: unable to open input file: "
       << ifile << endl;
  return -1;
} 

When we test a stream, the effect is to test whether the object is "okay: for input or output:

if (outfile)  //ok to use outfile?
if (!outfile)  //not ok to use outfile?

Rebinding a File Stream to a New File
Once a fstream has been opened, it remains associated with the specified file. To associate the fstream with a different file, we must first closethe existing file and then open a different file:
ifstream infile("in");    //open file named "in" for reading
infile.close();           //close "in"
infile.open("next");      //opens file named next for reading

The open function checks whether the stream is already open. If so, it sets its internal state to indicate that a failure has happened. Subsequent attempts to use the file stream will fail.

Clearing the State of a File Stream

Closing a stream does not change the internal state of the stream object. If the last read or write operation failed, the state of the object remains in a failure mode until we execute clear to reset the condition of the stream. After the clear, it is as if we had created the object afresh. (We should add clear after each close operation)

Two ways to read multiple files: 1. recreate the stream object for each file; 2. reuse the stream object and close/clear after each file.P 295

8.4.2 File Mode

Whenever we open a file, a file mode is specified. Different modes are represented by a set of values that can be controlled by bitwise operators:

File Modes
inopen for inputifstream/fstream
outopen outputofstream/fstream
appseek to the end before every writeofstream/fstream
ateseek to the end immediately after the openany file
trunctruncate an existing stream when opening itofstream/fstream
binarydo IO operations in binary modeany file
ate:has an effect only at the open: Opening a file in ate mode puts the file at the eof immediately after the open.

binary: process the file as a sequence of bytes; it does no interpretation of the characters in the stream.

in: by default, files associated with anifstream are opened inin mode. It permits the file to be read.

out: by default, files associated with an ofstream are opened in out mode. It permits the file to be written.A file opened in out mode is truncated: All data stored in the file is discarded. (in effect, specifying out mode for an ofstream is equivalent to specifying both out and trunc)

app: The only way to preserve the existing data in a file opened by an ofstream is to specify app mode explicitly

//output mode by default: truncates file named "file1"
ofstream outfile("file1");
// equivalent effect: "file1" is explicitly truncated
ofstream outfile2("file2", ofstream::out | ofstream::trunc);
// append mode: adds new data at the end of existing file named "file2"
ofstream outfile3("file3", ofstream::app);

Using the Same File for Input and Output   A.3.8(p.837)

An fstream object can both read and write its associated file. How an fstream uses its file depends on the mode specified when we open the file.

Mode Is an Attribute of a File, Not a Stream

So we need to set mode each time we open a file.

8.4.3 A Program to Open and Check Input Files

// opens in binding it to the given file
ifstream open_file(ifstream &in, const string &file)
{
  in.close();    //close in case it was already open
  in.clear();    //clear any existing errors
  // if the open fails, the stream will be in an invalid state
  in.open(file.c_str());  //open the file we were given
  return in;     //condition state is good if open succeeded
}

8.5 String Streams

The iostream library supports in-memory input/output, in which a stream is attached to a string within the program's memory. We should include sstream header to use these classes:

1. istringstream, derived from istream, reads from a string

2. ostringstream, derived from ostream, writes to a string

3. stringstream, derived from iostream, reads and writes the same string

sstream types have a constructor that takes a string. The constructor will copy the string argument into the stringstream object. These classes also define a member named str to fetch or set the string value that the stringstream manipulates.

stringstream-Specific Operations
stringstream strm;creates an unbound stringstream
stringstream strm(s);create a stringstream that holds a copy of the string s
strm.str()return a copy of the string that strm holds
strm.str(s)copies the string s into strm. return void

Using a stringstream

Some programs need to do some processing on a per-line basis and other works on each word within each line:

string line, word;            //will hold a line and word from input, respectively
while (getline(cin, line))    //read a line from the input into line
{
    //do per-line processing
    istringstream stream(line);  //bind stream to the line we read
    while (stream >> word)
    {
        //do per-word processing
    }
} 

stringstreams Provide Conversions and/or Formatting P 300

One common use of stringstream is when we want to obtain automatic formatting across multiple data types.

The sstream input and output operations automatically convert an arithmetic type into its corresponding string representation or back again

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值