C++Primer学习笔记08.IO库
### IO类<div align="center"><h6>IO库类型和头文件</h6></div>
| 头文件 | 类型 | 说明 |
| ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------- |
| iostream | istream、wistream 从流中读取<br>ostream、wostream 写到流中去<br>iostream、wiostream 可读可写 | 控制台输入输出流 |
| fstream| ifstream、wifstream 从文件中读取<br>ofstream、wofstream 写到文件中去 | 文件输入输出流 |
| sstream| istringstream、wistringstream 从 string 对象中读取<br>ostringstream、wostringstream 写到 string 对象中去<br>stringstream、wstringstream 对 string 对象进行读写 | string 对象的输入输出 |
w 开头的表示支持 wchar_t 类型的数据。且三个头文件的接口基本一致。
#### IO对象无拷贝或赋值
```cpp
ofstream out1, out2;
out1 = out2; // 错误:不能对流对象赋值
ofstream print(ofstream); // 错误:参数传递也是一种赋值的过程
out2 = print(out2); // 错误:不能拷贝流对象
```
读写一个 IO 对象会改变其状态,因此传递和返回的引用不能是 const。
#### 条件状态
IO 类所定义的一些函数和标志,可以帮助我们访问和操纵流的条件状态
<div align="center"><h6>IO库条件状态</h6></div>
| 状态 | 含义 |
| ------------------- | ----------------------------------------------------------------------------------------------- |
| strm::iostate | strm 是一种 IO 类型。iostate 是一种机器相关的类型,提供了表达条件状态的完整功能 |
| strm::badbit | 用来指出流已奔溃 |
| strm::failbit | 用来指出 IO 操作失败 |
| strm::eofbit | 用来指出流到达了文件结束 |
| strm::goodbit | 用来指出流末处于错误状态。辞职保证未零 |
| s.eof() | 若流 s 的 eofbit 置位,则返回 true |
| s.fail() | 若流 s 的 failbit ,则返回 true |
| s.bad() | 若流 s 的 badbit 置位,则返回 true |
| s.good() | 若流 s 处于有效状态,则返回 true |
| s.clear() | 将流 s 中所有条件状态位复位,将流的状态设置为有效。返回 void。 |
| s.clear(flags) | 根据给定的 flags 标志位,将流 s 中对应条件状态复位。flags 的类型位 strm::iostate。返回 void。 |
| s.setstate(flags) | 根据给定的 flags 标志位,将流 s 中对应条件状态置位。flags 的类型位 strm::iostate。返回 void。 |
| s.rdstate() | 返回流 s 的当前条件状态,返回值类型为 strm::iostate |
```cpp
auto old_state = cin.rdstate(); // 记录当前状态
cin.clear(); // 使 cin 有效
process_input(cin); // 使用 cin
cin.setstate(old_state); // 还原状态
```
复位 failbit 和 badbit
```cpp
cin.clear(cin.rdstate() & ~cin.failbit & ~cin.badbit);
```
#### 缓冲区
通过 io 库处理的流可能会立即刷新出去,也可能为暂存到系统缓冲区,缓冲区满时在处理。C++ 的 endl 可以显示的刷新缓冲区。cin 和 cout 交替执行也会触发缓冲区的刷新。
<span style="color:red">如果程序崩溃,输出缓冲区不会被刷新</span>
### 文件输入输出
| - | - |
| ------------------------ | --------------------------------------------------------------------------------- |
| fstream fstrm | 创建一个未绑定文件的文件流 |
| fstream fstrm(s) | 创建一个文件里,并打开名为 s 的文件。构造函数都是 explicit 的,因此没有隐式转换 |
| fstream fstrm(s, mode) | 指定了打开的模式 |
| fstrm.open(s) | 打开名为 s 的文件 |
| fstrm.close() | 关闭与 fstrm 绑定的文件,返回 void |
| fstrm.is_open() | 返回 bool,指出与 fstrm 关联的文件是否成功打开且未关闭 |
使用文件 IO 打开文件,并写入到另一个文件中去。
```cpp
#include<iostream>
#include <fstream>
void testWrite() {
std::ofstream fout("/home/xxx/cpp/primer/chapter08/helloc.txt");
std::string str;
std::cout << "请输入内容" << std::endl;
while (std::cin >> str) {
if (str == "886") {
break;
}
fout << str << std::endl;
}
std::cout << "write over!" << std::endl;
}
void testRead() {
std::ifstream fin("/home/xxx/cpp/primer/chapter08/helloc.txt");
std::string line;
if (fin.is_open()) {
while (getline(fin, line)) std::cout << line << std::endl;
}
}
int main() {
testWrite();
testRead();
}
```
close 方法时关闭当前当前关联的文件,关闭后就可以关联下一个文件了。
```cpp
void testClose() {
std::ifstream fin("/home/liujiawei/cpp/primer/chapter08/helloc.txt");
std::string line;
if (fin.is_open()) {
while (getline(fin, line)) std::cout << line << std::endl;
}
fin.close();
fin.open("/home/liujiawei/cpp/primer/chapter08/hello.txt");
if (fin.is_open()) {
while (getline(fin, line)) std::cout << line << std::endl;
}
}
```
如果 open 成功,则 open 会设置流的状态,使得 good() 为 true。
一份正确的 IO 流代码应该是考虑了各种错误情况,确保文件可以正常输入、输出的。
#### 文件模式
每个流都有一个关联的文件模式。
| 模式 | 说明 |
| -------- | ------------------------------------- |
| in | 读模式 |
| out | 写模式,会丢弃现有数据。 |
| app | 追加写 |
| ate | 打开文件时定位到文件末尾 |
| trunc| 截断文件,把一个文件的尾部砍掉。 |
| binary | 二进制方式进行 IO,适用于非文本数据 |
每次调用 open 时都会确定文件模式,文件隐式地以 out 模式打开。通常情况下,out 模式意味着同时使用 trunc 模式。
### string流
用 IO 的方式来处理 string。即内存 IO。istringstream 从 string 读取数据,ostringstream 向 string 写入数据,而头文件 stringstream 既可从 string 读数据也可向 string 写数据。
| - | - |
| ----------------- | ----------------------------------------- |
| sstream strm | 声明对象,但是没绑定 string |
| sstream strm(s) | 绑定了 string,构造方法都是 explicit 的 |
| strm.str() | 返回 strm 保存的 string 的拷贝 |
| strm.str(s) | 将 string s 拷贝到 strm 中,返回 void |
istringsteam 和 ostringstream 的具体用处不是很明白,书中只简单说了下<u>"用于读写给定 string 的字符串流"</u>。
```cpp
#include<iostream>
#include <sstream>
#include <vector>
struct PersonInfo {
std::string name;
std::vector<std::string> phones;
};
void testOS() {
std::string line;
std::ostringstream os;
while (std::cin >> line) {
if (line == "886") {
break;
}
os << line;
}
std::cout << os.str() << std::endl;
}
void testIS() {
std::string line, word;
std::vector<PersonInfo> people;
while (getline(std::cin, line)) {
if (line == "886") break;
PersonInfo info;
/**
* 将一个 istringstream 与刚刚读取的文本行进行绑定,
* 这样就可以在此 istringstream 上使用输入运算符来读取当前记录中的每个元素。
* 我们首先读取人名,随后用一个 while 循环读取此人的电话号码
* */
std::istringstream record(line);
record >> info.name;
while (record >> word)
info.phones.push_back(word);
people.push_back(info);
}
}
int main() {
testOS();
}
```
页:
[1]