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::iostate | strm is an IO type. iostate is a machine related type that provides complete functionality for expressing conditional states |
---|---|
strm::badbit | strm::badbit is used to indicate that the stream has crashed |
strm::failbit | strm::failbit is used to indicate that an IO operation has failed |
strm::eofbit | strm::eofbit is used to indicate that the stream has reached the end of the file |
strm::goodbit | strm::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
in | Open in read mode |
---|---|
out | Open as write |
app | Navigate to the end of the file before each write operation |
ate | Navigate to the end of the file immediately after opening the file |
trunc | truncate file |
binary | IO 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; } } }