8.1. 面向对象的标准库
IO 类型在三个独立的头文件中定义:iostream
定义读写控制窗口的类型,fstream
定义读写已命名文件的类型,而
sstream
所定义的类型则用于读写存储在内存中的 string
对象。在 fstream
和
sstream
里定义的每种类型都是从 iostream
头文件中定义的相关类型派生而来。
Header
Type
iostream
|
istream
从流中读取
ostream
写到流中去
iostream
对流进行读写;从 istream
和 ostream
派生而来
|
fstream
|
ifstream
从文件中读取;由 istream
派生而来
ofstream
写到文件中去;由 ostream
派生而来
fstream
读写文件;由 iostream
派生而来
|
sstream
|
istringstream
从 string
对象中读取;由
istream
派生而来
ostringstream
写到 string
对象中去;由
ostream
派生而来
stringstream
对 string
对象进行读写;由
iostream
派生而来
|
迄今为止,所描述的流类(stream class)读写的是由 char
类型组成的流。此外,标准库还定义了一组相关的类型,支持 wchar_t
类型。每个类都加上“w
”前缀
,以此与
char
类型的版本区分开来
。于是,wostream
、wistream
和
wiostream
类型从控制窗口读写 wchar_t
数据。相应的文件输入输出类是
wifstream
、wofstream
和 wfstream
。而 wchar_t
版本的
string
输入/输出流则是 wistringstream
、wostringstream
和
wstringstream
。标准库还定义了从标准输入输出读写宽字符的对象。这些对象加上“w
”前缀,以此与
char
类型版本区分:wchar_t
类型的标准输入对象是 wcin
;标准输出是
wcout
;而标准错误则是 wcerr
。
IO 对象不可复制或赋值
这个要求有两层特别重要的含义。正如在第九章
看到的,只有支持复制的元素类型可以存储在 vector
或其他容器类型里
。由于流对象不能复制
,因此不能存储在 vector
(或其他)容器中(即不存在存储流对象的 vector
或其他容器)
。
第二个含义是:形参或返回类型也不能为流类型
。如果需要传递或返回 IO 对象,则必须传递或返回指向该对象的指针或引用:
8.2. 条件状态
实现 IO 的继承正是错误发生的根源。一些错误是可恢复的;一些错误则发生在系统底层,位于程序可修正的范围之外。IO
标准库管理一系列条件状态(condition
state)
成员,用来标记给定的 IO 对象是否处于可用状态
,或者碰到了哪种特定的错误。表 8.2
列出了标准库定义的一组函数和标记,提供访问和操纵流状态的手段。
表 8.2. IO 标准库的条件状态
strm
::iostate
|
机器相关的整型名,由各个 iostream
类定义,用于定义条件状态
|
strm
::badbit
|
strm
::iostate
类型的值,用于指出被破坏的流
|
strm
::failbit
|
strm
::iostate
类型的值,用于指出失败的 IO 操作
|
strm
::eofbit
|
strm
::iostate
类型的值,用于指出流已经到达文件结束符
|
s.eof()
|
如果设置了流 s
的 eofbit
值,则该函数返回
true
|
s.fail()
|
如果设置了流 s
的 failbit
值,则该函数返回
true
|
s.bad()
|
如果设置了流 s
的 badbit
值,则该函数返回
true
|
s.good()
|
如果流 s
处于有效状态,则该函数返回 true
|
s.clear()
|
将流 s
中的所有状态值都重设为有效状态
|
s.clear(flag)
|
将流 s
中的某个指定条件状态设置为有效。flag
的类型是 strm
::iostate
|
s.setstate(flag)
|
给流 s
添加指定条件。flag
的类型是 strm
::iostate
|
s.rdstate()
|
返回流 s
的当前条件,返回值类型为 strm
::iostate
|
if
语句直接检查流的状态,而 while
语句则检测条件表达式返回的流,从而间接地检查了流的状态。如果成功输入,则条件检测为 true
。
int ival;
// read
cin
and test only for EOF; loop is executed even if there are other IO failures
while (cin >> ival, !cin.eof()) {
if (cin.bad()) // input stream is corrupted; bail out
throw runtime_error("IO stream corrupted");
if (cin.fail()) { // bad input
cerr<< "bad data, try again"; // warn the user
cin.clear(istream::failbit); // reset the stream
continue; // get next input
}
// ok to process
ival
}
8.3. 输出缓冲区的管理
系统将字符串字面值存储在与流 os
关联的缓冲区中。下面几种情况将导致缓冲区的内容被刷新,即写入到真实的输出设备或者文件:
程序正常结束
。作为 main
返回工作的一部分,将清空所有输出缓冲区。
在一些不确定的时候,缓冲区可能已经满了
,在这种情况下,缓冲区将会在写下一个值之前刷新。
用操纵符(第
1.2.2 节
)显式地刷新缓冲区,例如行结束符 endl
。
在每次输出操作执行完后,用 unitbuf
操作符设置流的内部状态,从而清空缓冲区
。
可将输出流与输入流关联(tie
)起来。在这种情况下,在读输入流时将刷新其关联的输出缓冲区
。
我们的程序已经使用过 endl
操纵符,用于输出一个换行符并刷新缓冲区。除此之外,C++
语言还提供了另外两个类似的操纵符。第一个经常使用的 flush
,用于刷新流,但不在输出中添加任何字符。第二个则是比较少用的
ends
,这个操纵符在缓冲区中插入空字符 null,然后后刷新它:
如果需要刷新所有输出,最好使用 unitbuf
操纵符。这个操纵符在每次执行完写操作后都刷新流:
cout << unitbuf << "first" << " second" << nounitbuf;
等价于:
cout << "first" << flush << " second" << flush;
nounitbuf
操纵符将流恢复为使用正常的、由系统管理的缓冲区刷新方式。
如果需要使用最后的输出给程序错误定位,则必须确定所有要输出的都已经输出。为了确保用户看到程序实际上处理的所有输出,
最好的方法是保证所有的输出操作都显式地调用了 flush
或 endl
。
将输入和输出绑在一起
tie
函数可用 istream
或 ostream
对象调用,使用一个指向 ostream
对象的指针形参。调用 tie
函数时,将实参流绑在调用该函数的对象上。如果一个流调用
tie
函数将其本身绑在传递给 tie
的 ostream
实参对象上,则该流上的任何 IO
操作都会刷新实参所关联的缓冲区。
一个 ostream
对象每次只能与一个 istream
对象绑在一起
。如果在调用
tie
函数时传递实参 0,则打破该流上已存在的捆绑。
8.4. 文件的输入和输出
fstream
类型除了继承下来的行为外,还定义了两个自己的新操作—— open
和
close
,以及形参为要打开的文件名的构造函数。fstream
、ifstream
或
ofstream
对象可调用这些操作,而其他的 IO 类型则不能调用
。
由于历史原因,IO 标准库使用 C 风格字符串(第 4.3 节
)而不是 C++
strings
类型的字符串作为文件名。在创建 fstream
对象时,如果调用 open
或使用文件名作初始化式,需要传递的实参应为 C 风格字符串,而不是标准库 strings
对象。程序常常从标准输入获得文件名。通常,比较好的方法是将文件名读入 string 对象,而不是 C 风格字符数组。假设要使用的文件名保存在
string
对象中,则可调用 c_str
成员(第 4.3.2 节
)获取 C 风格字符串。
检查文件打开是否成功
打开文件后,通常要检验打开是否成功,这是一个好习惯:
// check that the
open
succeeded
if (!infile) {
cerr << "error: unable to open input file: "
<< ifile << endl;
return -1;
}
将文件流与新文件重新捆绑
先关再开
,如:
ifstream infile("in"); // opens file named "in" for reading
infile.close(); // closes "in"
infile.open("next"); // opens file named "next" for reading
清除文件流的状态
如果希望避免在每次 while
循环过程中创建新流对象,可将 input
的定义移到
while
之前。这点小小的改动意味着必须更仔细地管理流的状态。如果遇到文件结束符或其他错误,将设置流的内部状态,以便之后不允许再对该流做读写操作。关闭流并不能改变流对象的内部状态。如果最后的读写操作失败了,对象的状态将保持为错误模式,直到执行
clear
操作重新恢复流的状态为止。调用 clear
后,就像重新创建了该对象一样。
ifstream input;
vector<string>::const_iterator it = files.begin();
// for each file in the
vector
while (it != files.end()) {
input.open(it->c_str()); // open the file
// if the file is ok, read and "process" the input
if (!input)
break; // error: bail out!
while(input >> s) // do the work on this file
process(s);
input.close(); // close file when we're done with it
input.clear(); // reset state to ok
++it; // increment iterator to get next file
}
如果程序员需要重用文件流读写多个文件,必须在读另一个文件之前调用 clear
清除该流的状态。
8.4.2. 文件模式
in
|
打开文件做读操作
|
out
|
打开文件做写操作
|
app
|
在每次写之前找到文件尾
|
ate
|
打开文件后立即将文件定位在文件尾
|
trunc
|
打开文件时清空已存在的文件流
|
binary
|
以二进制模式进行 IO 操作
|
从效果来看,为 ofstream
对象指定 out
模式等效于同时指定了
out
和 trunc
模式。
|
对同一个文件作输入和输出运算
fstream
对象既可以读也可以写它所关联的文件。fstream
如何使用它的文件取决于打开文件时指定的模式
。
默认情况下,fstream
对象以 in
和 out
模式同时打开。当文件同时以 in
和 out
打开时不清空。如果打开 fstream
所关联的文件时,只使用 out
模式,而不指定 in
模式,则文件会清空已存在的数据。如果打开文件时指定了
trunc
模式,则无论是否同时指定了 in
模式,文件同样会被清空。
下面的定义将 copyOut
文件同时以输入和输出的模式打开:
// open for input and output
fstream inOut("copyOut", fstream::in | fstream::out);
模式是文件的属性而不是流的属性
8.5. 字符串流
-
istringstream
,由 istream
派生而来,提供读
string
的功能。
-
ostringstream
,由 ostream
派生而来,提供写
string
的功能。
-
stringstream
,由 iostream
派生而来,提供读写
string
的功能。
表 8.5. stringstream
特定的操作
stringstream strm;
|
创建自由的 stringstream
对象
|
stringstream strm(s);
|
创建存储 s 的副本的 stringstream
对象,其中 s 是 string
类型的对象
|
strm.str()
|
返回 strm
中存储的 string
类型对象
|
strm.str(s)
|
将 string
类型的 s 复制给 strm
,返回
void
|
分享到:
相关推荐
C++Primer第五版 第8章 IO库(练习解答)个人总结的文档+源码,供学习参考之用,遗漏之处请参考我的博客
第八章 标准IO库 37 第九章 顺序容器 43 第十章 关联容器 60 第十一章 泛型算法 75 第十二章 类和数据抽象 86 第十三章 复制控制 94 第十四章 重载操作符与转换 102 第十五章 面向对象编程 116 第十六章 部分选做...
第8章 标准IO库 243 8.1 面向对象的标准库 244 8.2 条件状态 247 8.3 输出缓冲区的管理 249 8.4 文件的输入和输出 251 8.4.1 文件流对象的使用 251 8.4.2 文件模式 254 8.4.3 一个打开并检查输入文件的 程序 256 ...
本课程是C++ Primer初级教程,课程内容是学习C++语言基础知识,对应着教材的第1章到第8章。 第1章 快速入门 1.1 编写简单的C++程序 1.2 初窥输入/输出 1.2.1 标准输入与输出对象 1.2.2 一个使用IO库的程序 ...
1.下载和安装VC++2008 ...第8章面向对象的标准IO库 75.第8章条件状态 76.第8章文件流对象的使用 77.第8章重点习题解答 78.第8章文件模式 79.第8章一个打开并检查输入文件的程序 80.第8章字符串流
第8章 IO库 277 8.1 IO类 278 8.1.1 IO对象无拷贝或赋值 279 8.1.2 条件状态 279 8.1.3 管理输出缓冲 281 8.2 文件输入输出 283 8.2.1 使用文件流对象 284 8.2.2 文件模式 286 8.3 string流 287 ...
第8章 标准IO库 8.1 面向对象的标准库 8.2 条件状态 8.3 输出缓冲区的管理 8.4 文件的输入和输出 8.5 字符串流 小结 术语 第二部分 容器和算法 第9章 顺序容器 第10章 关联容器 ...
第8章 IO库 277 8.1 IO类 278 8.1.1 IO对象无拷贝或赋值 279 8.1.2 条件状态 279 8.1.3 管理输出缓冲 281 8.2 文件输入输出 283 8.2.1 使用文件流对象 284 8.2.2 文件模式 286 8.3 string流 287 ...
第8章 标准IO库 8.1 面向对象的标准库 8.2 条件状态 8.3 输出缓冲区的管理 8.4 文件的输入和输出 8.5 字符串流 小结 术语 第二部分 容器和算法 第9章 顺序容器 第10章 关联容器 ...
第8章 IO库 183 练习8.1~练习8.14 第9章 顺序容器 193 练习9.1~练习9.52 第10章 泛型算法 234 练习10.1~练习10.42 第11章 关联容器 273 练习11.1~练习11.38 第12章 动态内存 297 练习12.1~练习12.33 ...
,第8、9章最为重要,IO库和容器对于一个程序来说是比较基础的,记得不要在C++中还依然保持C的习惯,使用cout而不是printf()、使用vector而不是内置数组、使用迭代器进行遍历。第10、11章有点基础的看起来不是很难,...
The Solutions for C++ Primer 5th目录第I部分 C++基础第2章 变量和基本类型第3章 字符串、向量和数组第4章 表达式第5章 语句第6章 函数第7章 类第II部分 C++标准库第8章 IO库第9章 顺序容器第10章 泛型算法第11章 ...
37 第八章 标准IO库 ................................................................................................................................................. 37 第九章 顺序容器 ..................
##C++ 入门 5 个回答 笔记 编译时使用-std=c++11 (可选: -pedantic -Wall ...第 8 章 IO 库 第 9 章顺序容器 第 10 章通用算法 第 11 章关联容器 第三部分:课堂作者工具 第四部分:高级主题 第 19 章专用工具和技术
《Linux多线程服务端编程:使用muduo C++网络库》主要讲述采用现代C++在x86-64 Linux上编写多线程TCP网络服务程序的主流常规技术,重点讲解一种适应性较强的多线程服务器的编程模型,即one loop per thread。...