委员长 发表于 2025-1-5 12:11:02

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]
查看完整版本: C++Primer学习笔记08.IO库