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对象无拷贝或赋值
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 |
auto old_state = cin.rdstate(); // 记录当前状态
cin.clear(); // 使 cin 有效
process_input(cin); // 使用 cin
cin.setstate(old_state); // 还原状态
复位 failbit 和 badbit
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 打开文件,并写入到另一个文件中去。
#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 方法时关闭当前当前关联的文件,关闭后就可以关联下一个文件了。
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>。
#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();
}