[C + + learning] IO Library

Keywords: C++ Algorithm stream io

Part II C + + standard library

The core of the standard library is many container classes and a family of generic algorithms. These facilities can help us write concise and efficient programs. The standard library will pay attention to the details of bookkeeping operations, especially memory management, so that our programs can devote all their attention to the problems that need to be solved.

Chapter 8 IO Library

C + + language does not deal with input and output directly, but deals with IO through a family of types defined in the standard library. These types support IO operations of reading data from the device and writing data to the device. The device can be a file, console window, etc. There are also types that allow memory IO, that is, reading data from a string and writing data to a string.

8.1 IO class

IO library types and header files

Header file				type
iostream 		  istream,wistream Read data from stream
				  ostream,wostream Write data to stream
				  iostream,wiostream Read / write stream
fstream			  ifstream,wifstream Read data from file
				  ofstream,wofstream Write data to file
				  fstream,wfstream Read write file
sstream			  istringstream,wistringstream from string Read data
				  ostringstream,wostringstream towards string Write data
				  stringstream,wstringstream Reading and writing string

To support languages that use wide characters, the standard library defines a set of types and objects to manipulate wchar_ Data of type T. The names of types and functions in the wide character version start with a w. For example, wcin, wcout and wcerr are wide character version objects corresponding to cin, cout and cerr respectively. The types of wide character versions and objects are defined in the same header file as their corresponding ordinary char versions.

Relationship between IO types

Conceptually, neither the device type nor the string size will affect the IO operations we want to perform. For example, we can use > > to read data, regardless of whether it is from a console window, a disk file, or a string. Similarly, we don't care whether the read characters can be stored in a char object or need a wchar_t object to store.

The standard library enables us to ignore the differences between these different types of flows through inheritance. Using templates, we can use classes with inheritance relationships without having to understand the details of how the inheritance mechanism works.

The types ifstream and istringstream both inherit from istream. Therefore, we can use ifstream and istringstream objects just as we use istream objects. That is, how we use cin, we can use these types of objects in the same way. For example, you can call getline on an ifstream or istringstream object, or you can use > > to read data from an ifstream or istringstream object. Similarly, the types ofstream and ostringstream inherit from ostream. Therefore, we can use these types of objects the same way we all use cout.

8.1.1 IO object has no copy or assignment

We cannot copy or assign values to IO objects

ofstream out1, out2;
out1 = out2;		// Error: cannot assign value to stream object
ofstream print(ofstream);	// Error: unable to initialize ofstream parameter
out2 = print(out2);		// Error: cannot copy stream object

Since the IO object cannot be copied, we cannot set the formal parameter or return type to the stream type. Functions that perform IO operations usually pass and return streams by reference. Reading and writing an IO object will change its state, so the references passed and returned cannot be const.

8.1.2 condition status

An inherent problem with IO operations is that errors may occur. Some errors are recoverable, while others occur deep in the system and are beyond the scope of the application to correct.

IO library condition status

strm::iostatestrm is an IO type. iostate is a machine related type that provides complete functionality for expressing conditional states
strm::badbitstrm::badbit is used to indicate that the stream has crashed
strm::failbitstrm::failbit is used to indicate that an IO operation has failed
strm::eofbitstrm::eofbit is used to indicate that the stream has reached the end of the file
strm::goodbitstrm::goodbit is used to indicate that the stream is not in an error state. This value is guaranteed to be 0
s.eof()Returns true if eofbit of stream s is set
s.fail()Returns true if the failbit or badbit of stream s is set
s.bad()Returns true if the biabit of stream s is set
s.good()Returns true if stream s is in a valid state
s.clear()Reset all condition status bits in the stream s, set the state of the stream to valid, and return void
s.clear(flags)Reset the corresponding condition status bit in stream s according to the given flag bit. The type of flags is strm::iostate and returns void
s.setstate(flags)According to the given flag flag bit, the corresponding condition state position bit in stream s. The type of flags is strm::iostate. Return void
s.rdstate()Returns the current condition state of stream s, and the return value type is strm::iostate

Once a stream has an error, subsequent IO operations on it will fail. Only when a stream is in an error free state can we read data from it and write data to it. Since a stream may be in an error state, the code should usually check whether it is in good state before using a stream. The easiest way to determine the state of a stream object is to use it as a condition:

while(cin >> word)
    // ok: read operation succeeded

Status of query flow

The IO library defines a machine independent iostate type, which provides the complete function of expressing flow state. This type should be used as a set of bits. The IO library defines four constexpr values of iostate type to represent specific bit patterns. These values are used to represent specific types of IO conditions. They can be used with bit operators to detect or set multiple flag bits at one time.

Badbit indicates a system level error. In general, once badbit is set, the stream can no longer be used. After a recoverable error occurs, the failbit is set, and an error such as reading a character while reading the value as expected. This problem can usually be corrected and the stream can continue to be used. If the end of the file is reached, eofbit and failbit will be set. The value of goodbit is 0, indicating that there is no error in the stream. If badbit, failbit and eofbit are set, the condition to detect the flow state will fail.

The standard library also defines a set of functions to query the status of these flag bits. The operation good returns true when all error bits are not set, while bad, fail and eof return true when corresponding to the error bits. In addition, when badbit is set, fail will also return true. This means that using good or fail is the correct way to determine the overall state of the flow. In fact, the code that we use flow as a condition is equivalent to! fail(). eof and bad operations can only represent specific errors.

Management condition status

The rdstate member of the flow object returns an iostate value corresponding to the current state of the flow. The setstate operation will give the condition position bit, indicating that a corresponding error has occurred. The clear member is an overloaded member: it has a version that does not accept parameters, while another version accepts a parameter of type iostate.

Clear does not accept the version of the parameter. Clear (reset) all error flag bits. After executing clear(), calling good will return true.

auto old_state = cin.rdstate();		// Remember the current state of cin
cin.clear();						// Make cin effective
process_input(cin);					// Using cin
cin.setstate(old_state);			// Set cin to its original state

The clear version with parameters will accept an iostream value indicating the original state of the stream. In order to reset a single conditional state bit, we first read the current conditional state with rdstate, and then reset the required bit with bit operation to generate a new state

cin.clear(cin.rdstate() & ~cin.failbit & ~cin.badbit);	// Set failbit and badbit

8.1.3 manage output buffer

Each output stream manages a buffer to store data read and written by the program.

Flush output buffer

endl,flush,ends

cout << "hi!" << endl;		// Line feed refresh
cout << "hi!" << flush;		// Refresh
cout << "hi!" << ends;		// Null character refresh

unitbuf operator

If you want to flush the buffer after each output operation, you can use the unitbuf operator. It tells the stream to perform a flush operation after each subsequent write operation. The nounitbuf manipulator resets the flow. Restore it to the normal system managed buffer refresh mechanism:

cout << unitbuf;
cout << nounitbuf;

Associate input and output streams

When an input stream is associated with an output stream, any attempt to read data from the input stream will refresh the associated output stream first. The standard library associates cout and cin.

Tie has two overloaded versions: one version takes no parameters and returns a pointer to the output stream. If the object is currently associated with an output stream, it returns a pointer to the stream. If the object is not associated with a stream, it returns a null pointer. The second version of tie accepts a pointer to the ostream and associates itself with it.

We can associate an istream object with another ostream or an ostream with another ostream:

ostream *old_tie = cin.tie(nullptr);	// old_tie points to the flow (if any) currently associated with cin, and cin is no longer associated with other flows

Each flow can be associated with at most one flow at the same time, but multiple flows can be associated with the same ostream at the same time.

8.2 document input and output

The header file fsstream defines three types to support file IO: i fstream reads data from a given file, ofstream writes data to a given file, and fsstream can read and write to a given file.

fstream specific operations

fstream fstrm;			Create an unbound file stream. fstream Is a header file fstream A type defined in
fstream fstrm(s);		Create a fstream,And open the file named s File. s Can be string Type, or						  One point C Pointer to the style string. These constructors are explicit of Default text						  Component mode depends on fstream Type of
fstream fstrm(s, mode);	Similar to the previous constructor, but specifying mode Open the file.
fstrm.open(s);			Open named s And compare the file with fstrm Binding. s Can be a string Or one						 point C Pointer to the style string. Default file mode Depend on fstream Type of. return						  void
fstrm.close();			Close on fstrm Bind file. return void
fstrm.is_open();		Return a bool Value, indicating and fstrm Whether the associated file was successfully opened and not closed.

8.2.1 using file stream objects

When creating a file stream object, we can provide a file name. If a file name is provided, open is called automatically.

ifstream in(file);		// Construct an ifstream and open the given file
ofstream out;			// The output file stream is not associated with any files

Fsstream instead of iostream&

Functions that accept an iostream type reference (or pointer) parameter can be called with a corresponding fsstream (or s sstream) type.

Member functions open and close

If we define an empty file flow object, we can then call open to associate it with the file:

ifstream in(ifile);		// Build an ifstream and open the given file
ofstream out;			// The output file stream is not associated with any files
out.open(ifile + ".copy");	// Open the specified file

If the call to open fails, the failbit will be set. Because the call to open may fail, it is usually a good habit to check whether the open is successful:

if(out)		// Check whether open is successful
    		// open succeeded. We can use the file

Once a file stream has been opened, it remains associated with the corresponding file. In fact, calling open on an open file stream will fail and cause the failbit to be set. Subsequent attempts to use the file stream will fail. In order to associate a file to another file, you must first close the associated file. Once the file is successfully closed, we can open a new file:

in.close();
in.open(ifile + "2");

Automatic construction and Deconstruction

for(auto p = argv + 1; p != argv + argc; ++ p){
    ifstream input(*p);
    if(input){
        process(input);
    }else{
        cerr << "couldn't open: " + string(*p);
    }
}// Each loop step input will leave the scope, so it will be destroyed

When an fstream object is destroyed, close will be called automatically

8.2.2 document mode

File mode

inOpen in read mode
outOpen as write
appNavigate to the end of the file before each write operation
ateNavigate to the end of the file immediately after opening the file
trunctruncate file
binaryIO in binary mode
  • You can only set out mode on ofstream or fsstream objects.
  • in mode can only be set on i fstream or fsstream objects.
  • The trunc mode can be set only when out is also set.
  • You can set the app mode only if runc is not set. In app mode, even if the specified out mode is not displayed, the file is always opened as output.
  • By default, even if trunc is not specified, files opened in out mode will be truncated. In order to preserve the contents of the file opened in out mode, we must also specify the app mode, which will only append the data to the end of the file; Or specify the in mode at the same time, that is, read and write while opening the file.
  • The ate and binary modes can be used for any type of file stream object and can be used in combination with other file modes.

Opening a file in out mode discards existing data

// truncation
ofstream out("file1");
ofstream ou12("file1", ofstream::out);
ofstream out3("file1", ofstream::out | ofstream::trunc);
// retain
ofstream app("file2", ofstream::app);
ofstream app2("file2", ofstream::out | ofstream::app);

The only way to preserve the existing data in the file opened by ofstream is to explicitly specify the app or in mode.

The file mode is confirmed each time open is called

For a given stream, the file format can be changed whenever a file is opened.

ofstream out;	// File open mode is not specified
out.open("scratchpad");	// The mode is implicitly set to output and truncation
out.close();	// Close out so that we can use it for other files
out.open("precious", ofstream::app);	// The modes are output and append
out.close();

8.3 string stream

The s sstream header file defines three types to support memory IO. istringstream reads data from string, ostringstream writes data to string, and the header file stringstream can read data from string and write data to string.

stringstream specific operations

sstream strm;		strm Is an unbound stringstream Object, sstream Is a header file sstream definition					  A type of.
sstream strm(s);	strm It's a sstream Objects, saving string s A copy of. This constructor is							explicit of
strm.str()			return strm Saved string Copy of
strm.str(s)			take string s copy to strm Yes. return void

8.3.1 using istringstream

istringstream is usually used when some of our work is to process the whole line of text, while others are to process the words in the line.

string line, word;
vector<PersonInfo> people;
while(getline(cin, line)){
    PersonInfo info;
    istringstream record(line);		// Convert read row to istringstream
    record >> info.name;
    while(record >> word)			// Read word by word from istringstream
        info.phones.push_back(word);
    people.push_back(info);
}

8.3.2 using ostringstream

for(const auto &entry : people){
    ostringstream formatted, badNums;
    for(const auto &nums : entry.phones){
        if(!valid(nums)){
            badNums << " " << nums;
        }else{
            formatted << " " << format(nums);
        }
        if(badNums.str().empty()){
            os << entry.name << " " << formatted.str() << endl;
        }{
            cerr << "input error: " << entry.name << " invalid number(s) "
                << badNums.str() << endl;
        }
    }
}


Posted by clodagh2000 on Mon, 29 Nov 2021 20:56:48 -0800