The IO Library

The IO Classes

The IO types and objects that we have used so far manipulate char data. By default these objects are connected to the user’s console window. Of course, real programs cannot be limited to doing IO solely to or from a console window. Programs often need to read or write named files. Moreover, it can be convenient to use IO operations to process the characters in a string. Applications also may have to read and write languages that require wide-character support.

To support these different kinds of IO processing, the library defines a collection of IO types in addition to the istream and ostream types that we have already used. These types are defined in three separate headers:

Header use
iostream read from and write to a stream
fstream read and write named files
sstream read and write in-memory strings

As we saw in previous, we cannot copy or assign objects of the IO types, so we cannot have a parameter or return type that is one of the stream types. Functions that do IO typically pass and return the stream through references.

Inherent in doing IO is the fact that errors can occur. Some errors are recoverable; others occur deep within the system and are beyond the scope of a program to correct. The IO classes define functions and flags let us access and manipulate the condition state of a stream.(*stream represent one of streams in previous table)

name meaning
*stream::iostate Type for stream state flags
*stream::eofbit End-Of-File reached while performing an extracting operation on an input stream.
*stream::failbit The last input operation failed because of an error related to the internal logic of the operation itself.
*stream::badbit Error due to the failure of an input/output operation on the stream buffer.
*stream::goodbit No error. Represents the absence of all the above (the value zero).

The more details you can read in here.

As an example of an IO error, consider the following code:int ival; cin >> ival;, If we enter Boo on the standard input, the read will fail. The input operator expected to read an int but got the character B instead. As a result, cin will be put in an error state. Similarly, cin will be in an error state if we enter an end-of-file. Once an error has occurred, subsequent IO operations on that stream will fail. We can read from or write to a stream only when it is in a non-error state.

File Input and Output

The fstream header defines three types to support file IO: ifstream to read from a given file, ofstream to write to a given file, and fstream, which reads and writes a given file. These types provide the same operations as those we have previously used on the objects cin and cout. In particular, we can use the IO operators (<< and >>) to read and write files, we can use getline to read an ifstream.

In addition to the behavior that they inherit from the iostream types, the types defined in fstream add members to manage the file associated with the stream. These operations, listed in next table, can be called on objects of fstream, ifstream, or ofstream but not on the other IO types.

use meaning
fstream fstrm; created a unbound file stream.
fstream fstrm(s); created a file stream and open file called s
fstream fstrm(s,mode); like previous, but with special mode.
fstrm.open(s) Opens the file identified by argument filename
fstrm.open(s,mode) like previous, but with special mode.
fstrm.close() Closes the file currently associated with the object, disassociating it from the stream.
fstrm.is_open() Returns whether the stream is currently associated to a file.

When we want to read or write a file, we define a file stream object and associate that object with the file. Each file stream class defines a member function named open that does whatever system-specific operations are required to locate the given file and open it for reading or writing as appropriate.

When we create a file stream, we can (optionally) provide a file name. When we supply a file name, open is called automatically, this is a simple example that create question and answer question program, the question and answer will be save in file.

#include <iostream>
#include <fstream>
#include <string>

int main() {
    //file path
    std::string ans_file = "Answer.txt";
    std::string que_file = "Question.txt";

    // created question
    std::ifstream in;
    std::ofstream out;
    out.open(que_file);
    out << 300 << " " << 400;
    out.close();

    //answer the question
    in.open(que_file);
    int num1, num2, sum;
    in >> num1 >> num2;
    sum = num1 + num2;
    out.open(ans_file);
    out << sum;

    //read answer
    in.close();
    in.open(ans_file);
    in >> sum;
    std::cout << sum << std::endl;
    return 0;
}

When we define an empty file stream object, we can subsequently associate that object with a file by calling open, If a call to open fails, failbit is set. Because a call to open might fail, it is usually a good idea to verify that the open succeeded:

if(out){
    /**/
}

Once a file stream has been opened, it remains associated with the specified file. Indeed, calling open on a file stream that is already open will fail and set failbit. Subsequent attempts to use that file stream will fail. To associate a file stream with a different file, we must first close the existing file. Once the file is closed, we can open a new one.

Each stream has an associated file mode that represents how the file may be used. Next table lists the file modes and their meanings.

member constant stands for access
in input File open for reading: the internal stream buffer supports input operations.
out output File open for writing: the internal stream buffer supports output operations.
binary binary Operations are performed in binary mode rather than text.
ate at end The output position starts at the end of the file.
app append All output operations happen at the end of the file, appending to its existing contents.
trunc trunc ate Any contents that existed in the file before it is open are discarded.

We can supply a file mode whenever we open a file—either when we call open or when we indirectly open the file when we initialize a stream from a file name. The modes that we can specify have the following restrictions:

  1. out may be set only for an ofstream or fstream object.
  2. in may be set only for an ifstream or fstream object.
  3. trunc may be set only when out is also specified
  4. app mode may be specified so long as trunc is not. If app is specified, the file is always opened in output mode, even if out was not explicitly specified.
  5. The ate and binary modes may be specified on any file stream object type and in combination with any other file modes.

By default, when we open an ofstream, the contents of the file are discarded. The only way to prevent an ostream from emptying the given file is to specify app.

string Streams

The sstream header defines three types to support in-memory IO; these types read from or write to a string as if the string were an IO stream.

The istringstream type reads a string, ostringstream writes a string, and stringstream reads and writes the string. Like the fstream types, the types defined in sstream inherit from the types we have used from the iostream header. In addition to the operations they inherit, the types defined in sstream add members to manage the string associated with the stream. These operations are listed in next table. They may be called on stringstream objects but not on the other IO types.

use meaning
sstream strm; unbound string stream
sstream strm(s); string stream bound to string s
strm.str() return a string that strm holds
strm.str(s) copy string s to strm

An istringstream is often used when we have some work to do on an entire line, and other work to do with individual words within a line.

As one example, assume we have a file that lists people and their associated phone numbers. Some people have only one number, but others have several—a home phone, work phone, cell number, and so on. Our input file might look like the following:morgan 2015552368 8625550123, drew 9735550130, lee 6095550132 2015550175 8005550000.

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
class Info {
    public:
    //constructor
    Info(std::string n) : name(n) {}

    //add more phone number
    void add_phone(std::string ph) {
        phone.push_back(ph);
    }

    //print information
    void print(std::ostream& os) {
        os << "Name: " << "\n";
        int count = 1;
        for (auto i = phone.begin(); i < phone.end(); i++) {
            os << "phone" << count << ": " << *i << "\n";
        }
        os << "\n";
    }
    private:
    std::string name;
    std::vector<std::string> phone;
};

int main() {
    std::istringstream in;
    std::string info;
    std::vector<Info> contacts;
    while (getline(std::cin,info)) {
        in.str(info);
        std::string name;
        std::string phone_number;
        // read name and create contact
        in >> name;
        Info peo(name);
        //read phone number
        while (in >> phone_number) {
            peo.add_phone(phone_number);
        }
        contacts.push_back(peo);
        for (auto i = contacts.begin(); i < contacts.end(); i++) {
            i->print(std::cout);
        }
    }
    return 0;
}

life is perfact