CPPprimer第八章IO库
CPPprimer第八章IO库
Hoshea ZhangC++语言不直接处理输入输出,而是通过一组定义在标准库中的class类型,即 流类类型(stream class type) 来处理IO操作。这些类支持从设备读取数据、向设备写入数据的IO操作,设备可以是文件、控制台窗口等,还有一些类允许内存IO,即,从内存读取数据,向内存写入数据。
IO 库定义了读写内置类型值的操作。除此之外,一些类,比如 string ,通常也会定义类似的IO操作,来读写class类型自己的对象。
istream 输入流类型,提供输入操作。
ostream 输出流类型,提供输出操作。
cin 一个 istream 对象,从标准输入读取数据。
cout 一个 ostream 对象,向标准输出写入数据。
cerr 一个 ostream 对象,用户输出程序错误消息,写入到标准错误。
>> 运算符,用来从一个 istream 对象读取输入数据。
\<< 运算符,用来从一个 ostream 对象写入输出数据。
getline函数,从一个给定的 istream 读取一行数据,存入一个给定的 string 对象中。
IO类
头文件 | 类型 |
---|---|
iostream | istream,wistream 从流中读取数据 ostream,wostream 向流中写入数据 iostream,wiostream 读写流 |
fstream | ifstream,wifstream 从文件中读取数据 ofstream,wofstream 向文件中写入数据 fstream,wfstream 读写文件 |
sstream | istringstream,wistringstream 从 string 对象中读取数据 ostringstream,wostringstream 向 string 对象中写入数据 stringstream,wstringstream 读写 string 对象 |
文件输入输出
头文件 fstream 定义了三个类型来支持文件IO:ifstream从一个给定文件读取数据,ofstream向一个给定文件写入数据,以及fstream可以读写给定文件。在17.5.3节中将介绍如何对同一个文件流既读又写。
这些类型提供的操作与之前已经使用过的对象cin和cout的操作一样。特别是可以用IO运算符(<<和>>)来读写文件,可以用getline函数从一个ifstream读取数据。也就是说,包括8.1节中介绍的操作也都适用于这些类型。
除了继承自iostream类型的行为之外,头文件 fstream 中定义的类型还增加了一些新的成员来管理与流关联的文件。在下面列出了这些操作,我们可以对fstream,ifstream和ofstream对象调用这些操作,但不能对其他IO类型调用这些操作。
使用文件流对象
1 | ifstream in(ifile); // 构造一个 ifstream 对象,打开给定文件并将双方绑定 |
这段代码定义了一个输入流 in ,它被初始化为从文件读取数据,文件名由参数 ifile 指定。第二条语句定义了一个输出流out,未与任何文件关联。在新C++标准中,文件名既可以是库类型string对象,也可以是C风格字符数组(参见3.5.4节)。旧版本的标准库只允许C风格字符数组。
open和close函数
1
2
3ifstream in(ifile); // 构筑一个ifstream并打开给定文件
ofstream out; // 输出文件流未与任何文件相关联
out.open(ifile + ".copy"); // 打开指定文件这个条件判断与我们之前将cin用作条件相似。如果open失败,条件会为假,我们就不会去使用out了。
一旦一个文件流已经打开,它就保持与对应文件的关联。实际上,对一个已经打开的文件流调用open会失败,并会导致 failbit 被置位。而随后的试图使用该文件流的操作自然都会失败。 为了将文件流关联到另外一个文件,必须首先关闭已经关联的文件。一旦文件成功关闭,我们可以打开新的文件:
1
2in.close(); // 关闭文件
in.open(ifile + "2"); // 打开另一个文件
文件模式
每个流都有一个关联的文件模式(file mode),用来指出如何使用文件。下面列出了文件模式和它们的含义。
文件模式 | 含义 |
---|---|
in |
以读方式打开 |
out |
以写方式打开 |
app |
每次写之前定位到文件末尾(追加) |
ate |
打开文件后立即定位到文件末尾 |
trunc |
截断文件 |
binary |
以二进制方式进行 IO 操作 |
有的文件模式可以同时指定。
通过|
可以组合文件模式,比如:ofstream::out | ofstream::trunc
以out模式打开文件会丢弃已有数据
1 | // 在这几条语句中,filel都被截断 |
string流
头文件 sstream 定义了三个类型来支持内存IO,这些类型可以向string写入数据,从string读取数据,就像string是一个IO流一样。
istringstream从string读取数据,ostringstream向string写入数据,而stringstream既可从string读数据也可向string写数据。与头文件fstream类似,头文件sstream中定义的类型都继承自iostream头文件定义的类型。除了继承得来的操作,sstream中定义的类型还增加了一些成员来管理与流相关联的string。
头文件sstream中定义的这些类型的单参数构造函数都是explicit的,,即不能通过隐式转换参数。
istringstream
应用举例:
1 | string line,word; // 分别来自输入的一行和单词 |
这里用 getline 从标准输入读取整条记录。如果 getline 函数调用成功,那 么 line 中将保存着从输入文件而来的一条记录。在 while 中定义了一个局部Personlnfo对象,来保存当前记录中的数据。
接下来将一个 istringstream 与刚刚读取的文本行进行绑定,这样就可以在 此 istringstream 上使用输入运算符来读取当前记录中的每个元素。首先读取人名,随后用一个 while 循环读取此人的电话号码。
当读取完line中所有数据后,内层 while 循环就结束了。此循环的工作方式与前面章节中读取 cin 的循环很相似,不同之处是,此循环从一个 string 而不是标准输入 读取数据。当 string 中的数据全部读出后,同样会触发“文件结束”信号,在 record 上的下一个输入操作会失败。
将刚刚处理好的Personinfo追加到 vector 中,外层 while 循环的一个循环步就随之结束了。外层 while 循环会持续执行,直至遇到 cin 的文件结束标识。
ostringstream
1 | for (const auto &entry : people) // 对people中每一项 |