第8章 IO库

第8章 IO库

1 IO类

标准库定义的IO类型如下图:iostream定义了用于读写流的基本类型;fstream定义了读写命名文件的类型;sstram定义了读写内存string对象的类型。

1.1 IO对象无拷贝或赋值

1
2
3
4
ofstream out1, out2
out1 = out2; // 错误,不能对流对象赋值
ofstream print(ofstream); //错误,不能初始化 ofstream参数
out2 = print(out2); // 错误,不能拷贝流对象

由于不能拷贝IO对象,因此不能将形参或返回类型设置为流类型。进行IO操作的函数通常以引用方式传递和返回流。

1.2 条件状态

IO操作一个与生俱来的问题是可能发生错误,因此代码通常应该在使用流之前检查它是否处于良好状态。最简单的方法是将它当作条件使用:while (cin>>word)

此外,IO库定义了一个与机器无关的iostate类型,然后定义了4个iostate类型的constexpr值,用来表示特点类型的IO条件,可以通过其查询流的状态;同意还提供了成员函数以管理条件状态

1.3 管理输出缓冲

每个输出流都管理一个缓冲区,用来保存程序读写的数据。有了缓冲机制,操作系统就可以将程序的多个输出操作组合成单一的系统及写操作。

刷新输出缓冲区

刷新输出缓冲区(即,数据真正写到输出设备或文件)的操纵符:

  • endl,添加换行,再刷新缓冲区

  • flush,刷新缓冲区,不附加任何额外字符

  • ends,插入空字符,再刷新缓冲区

如果想在每次输出操作后都刷新缓冲区,可以使用unitbuf操作符。它告诉流在接下来的每次写操作之后都执行依次flush操作。

关联输入和输出流

​ 当一个输入流被关联到一个输出流时,任何试图从输入流读取数据的操作都会先刷新关联的输出流。

2 文件输入输出

fstream继承自iostream类型,因此可以使用cin、cout、<<、>>等操作,此外,还增加了一些新的成员:

2.1 使用文件流对象

当我们想要读写一个文件时,可以定义一个文件流对象,并将对象与文件关联起来 。

1
ifstream in(ifile); //构造一个ifsteam并打开给定文件

fstream代替iostream&

在要求使用基类型对象的地方,可以用继承类型的对象来代替。如果有一个函数接受一个ostream&参数,可以传递给它一个ofstream对象,对istreamifstream也是如此。

成员函数openclose

如果定义了一个空文件流对象,随后可以调用open将它与文件关联

1
2
ofstream out;   // 输出流未与任何文件相关联
out.open(ifile + ".copy"); // 打开指定文件

一旦一个文件流已经打开,它就保持与对应文件的关联。为了将文件流关联到另外一个文件,必须首先关闭已经关联的文件。

1
2
in.close(); // 关闭文件
in.open(ifile + "2"); // 打开另一个文件

2.2 文件模式

每个流都有一个关联的文件模式,用来指出如何使用文件。

out模式打开文件会丢弃已有数据

保留被ofstream打开的文件中已有数据的唯一方法是显示指定appin模式。

3 string流

fstream类似,头文件sstream中定义的类型都继承自iostream中定义的类型。除了继承得来的操作,sstream中定义的类型还增加了一些成员来管理与流相关联的string

3.1 使用istringstream

考虑这样一个例子,假定有一个文件,列出来一些人和电话号码:

1
2
3
morgan 13681311344 18845772394
drew 15655168523
lee 18856565240 137117751575 15655432874

首先定义一个类来描述输入数据:

1
2
3
4
struct PersonInfo {
string name;
vector<string> phones;
};

然后读取文件,并创建一个PersonInfo的vector:

1
2
3
4
5
6
7
8
9
10
string line,word; // 分别保存来自输入的一行和单词
vector<PersonInfo> people; // 保存输入的所有记录
while (getline(cin, line)) {
PersonInfo info; // 创建一个保存此记录数据的对象
istringstream record(line); // 将记录绑定到刚读入的行
record >> info.name; // 读取名字
while (record >> word) // 读取电话号码
info.phones.push_back(word); // 保持它们
people.push_back(info); // 将此记录追加到people末尾
}

3.2 使用ostringstream

现在对每个人验证其电话号码是否有效并改变其格式,对于无效号码,输出人名和错误信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
for (const auto &entry : people) {
ostringstream formatted, badNums;
for(const auto &nums : entry.phones){
if (!vaild(nums))
badNums << " " <<nums; // 将数的字符串形式存入badNums
else
formatted << " " << format(nums); // 将格式化的字符串形式写入formatted
}
if (badNums.str().empty())
os << entry.name << " "
<< formatted.str() << endl;
else
cerr << "inpur error: " << entry.name
<< "invalid number(s) "<< badNums.str() << endl;
}

此程序中,假定已有两个函数,valid和format,用于验证和格式化。


第8章 IO库
https://kingw413.github.io/2023/08/26/Ch8-IO库/
作者
Whd
发布于
2023年8月26日
许可协议