第8章 标准IO库
1. IO标准库有几种类型?分别包含在什么头文件中?它们之间的关系怎样(画图)?它们应用的场合怎样?
答:三个头文件:
- iostream:定义读写控制窗口的类型
- fstream:定义读写已命名文件的类型。
- sstream:读写内存中string对象
九种类型:
iostream头文件中定义了istream、ostream、iostream三种类型
fstream头文件中定义了ifstream、ofstream、fstream三种类型
sstream头文件中定义了istringstream、ostringstream、stringstream三种类型
它们之间的继承关系如下:
它们的应用场合为:
istream(从流中读取);
ostream(写到流中);
iostream(对流进行读写);
ifstream(从文件中读取);
ofstream(写到文件中去);
fstream(对文件进行读写);
istringstream(从string对象中读取);
ostringstream(写到string对象中去);
stringstream(对string对象进行读写);
2. IO标准库是否支持国际化?如何支持?IO类型是否支持复制或赋值?不能复制有什么影响?
答:支持。
标准库定义了一组相关的类型,支持wchar_t类型。每个类都加上“w”前缀,以此与char类型的版本区分开来。于是,wostream,wistream和wiostream类型从控制窗口读写wchar_t数据。相应的文件输入输出类是wifstream,wofstream和wfstream。而wchar_t版本的string输入/输出流则是wistringstream,wostringstream,wstirngstream。标准库还定义了从标准输入输出读写宽字符的对象。这些对象加上"w"前缀,以此与char类型的版本区分:wchar_t类型的标准输入对象是wcin;标准输出是wcout;而标准错误则是wcerr。每个IO头文件都定义了char和wchar_t类型的类和标准输入/输出对象。基于流的wchar_t类型的类和对象在iostream中定义,宽字符文件流类型在fsteam中定义,而宽字符stringstream则在sstream头文件中定义。
IO标准库不可复制或赋值。不能复制有以下影响:
- 只有支持复制的元素类型可以存储在vector或其他容器类型里。由于流对象不能复制,因此不能存储在vector(或其他)容器中;
- 形参或返回类型也不能为流类型。若需要传递或返回IO对象,则必须传递或返回指向该对象的指针或引用。一般情况下,如果要传递IO对象以便对它进行读写,可用非const引用的方式传递这个流对象。对IO对象的读写会改变它的状态,因此引用必须是非const的。
3. stream中的状态有哪几种?在哪个状态常量中定义?如何获取这些状态?如何设置这些状态?什么场合会设置相应的状态?
答:stream中的状态有:被破坏的流、失败的IO操作、已经到达文件结束符的流;
有以下状态常量,分别定义了stream中的三种状态(strm代表流的类型,如 ifstream等):
- strm::badbit strm::iostate类型的值,用于指出被破坏的流
- strm::failbit strm::iostate类型的值,用于指出失败的IO操作
- strm::eofbit strm::iostate类型的值,用于指出流已经到达文件结束符
可通过以下函数获得这些状态(s是流对象,如cin):
s.eof() 如果设置了流 s 的 eofbit 值,则该函数返回 trues.fail() 如果设置了流 s 的 failbit 值,则该函数返回 true
s.bad() 如果设置了流 s 的 badbit 值,则该函数返回 true
s.good() 如果流 s 处于有效状态,则该函数返回 true
s.rdstate() 返回流 s 的当前条件,返回值类型为 strm::iostate; 如:istream::iostate old_state = cin.rdstate();
可以用如下函数设置上面的状态:
s.setstate(flag) 开启流s条件状态中对应的状态位。flag 的类型是 strm::iostate
s.clear() 将流 s 中的所有状态值都重设为有效状态
s.clear(flag) 将流 s 中的某个指定条件状态设置为有效。flag 的类型是strm::iostate
以下场合会设置相应的状态:
- badbit 标志着系统级的故障,如无法恢复的读写错误。如果出现了这类错误,则该流通常就不能再继续使用了。
- 如果出现的是可恢复的错误,如在希望获得数值型数据时输入了字符,此时则设置 failbit 标志,这种导致设置 failbit的问题通常是可以修正的。
- eofbit 是在遇到文件结束符时设置的,此时同时还设置了 failbit。
4. stream中的缓冲区有哪五种刷新场合?缓冲区刷新操纵符有哪四种?有何区别?为什么用endl而不用"\n"?
答:下面几种情况将导致缓冲区的内容被刷新,即写入到真实的输出设备或者文件:
1. 程序正常结束。作为 main 返回工作的一部分,将清空所有输出缓冲区。
2. 在一些不确定的时候,缓冲区可能已经满了,在这种情况下,缓冲区将会在写下一个值之前刷新。
3. 用操纵符显式地刷新缓冲区,例如行结束符 endl。
4. 在每次输出操作执行完后,用 unitbuf 操作符设置流的内部状态,从而清空缓冲区。
5. 可将输出流与输入流关联(tie)起来。在这种情况下,在读输入流时将刷新其关联的输出缓冲区。
缓冲区刷新操纵符有: endl 操纵符,用于输出一个换行符并刷新缓冲区。
flush,用于刷新流,但不在输出中添加任何字符。
ends,这个操纵符在缓冲区中插入空字符 null,然后后刷新它。
unitbuf 操纵符,这个操纵符在每次执行完写操作后都刷新流。如果需要刷新所有输出,最好使用
unitbuf 操纵符。
cout << "hi!" << flush; // 刷新流,但不在输出中添加任何字符
cout << "hi!" << ends; //在缓冲区中插入空字符 null,然后后刷新它
cout << "hi!" << endl; //用于输出一个换行符并刷新缓冲区
cout << unitbuf << "first" << " second" << nounitbuf;//等价于:cout << "first" << flush << " second" << flush;
如果需要使用最后的输出给程序错误定位,则必须确定所有要输出的都已经输出。为了确保用户看到程序实际上处理的所有输出,输出时应多使用 endl 而非 '\n'。使用endl 则不必担心程序崩溃时输出是否悬而未决(即还留在缓冲区,未输出到设备中)。
5. 如何将输入和输出绑定?绑定的作用是什么?
答:使用tie函数来绑定输入和输出。tie 函数可用 istream 或 ostream 对象调用,使用一个指向 ostream 对象的指针形参。调用 tie 函数时,将实参流绑在调用该函数的对象上。如果一个流调用 tie 函数将其本身绑在传递给 tie 的 ostream 实参对象上,则该流上的任何 IO 操作都会刷新实参所关联的缓冲区。
当输入流与输出流绑在一起时,任何读输入流的尝试都将首先刷新其输出流关联的缓冲区,即任何输出都在试图读之前输出。
cin.tie(&cout);
cin.tie(0); // break tie to cout, cout no longer flushed when cin is read
6. 如何打开文件?如何检查文件是否被打开?如何将文件重新捆绑?如何清除文件状态?什么场合需要清除文件状态?文件打开的模式有哪几种?
答:假设ifile 和 ofile 是存储希望读写的文件名的 string对象:
ifstream infile(ifile.c_str());
ofstream outfile(ofile.c_str());
为 ifstream 或者 ofstream 对象提供文件名作为初始化式,就相当于打开了特定的文件。
如果只是定义了流对象,而没有捆绑具体的文件名,则在使用对象之前必须用open函数使流对象捆绑到特定的文件上。
infile.open("in");
outfile.open("out");
可以将流对象做为if语句的判断条件,来检验文件是否被打开:
if (!infile) {
cerr << "error: unable to open input file: "
<< ifile << endl;
return -1;
}
或者if (outfile) // ok to use outfile?
fstream 对象一旦打开,就保持与指定的文件相关联。如果要把 fstream 对象与另一个不同的文件关联,则必须先关闭(close)现在的文件,然后打开(open)另一个文件:要点是在尝试打开新文件之前,必须先关闭当前的文件流。input.open("infile"); input.close(); input.open("next");
可以通过clear()函数清除文件状态,如:input.clear();以下场合需要清除文件状态:
确定在重新捆绑之前流对象的状态有可能被设置为错误 模式,例如遇到文件结束符或其他错误就会将流对象的状态位重新设置,这样,之后就不允许再对该流做读写操作,所以如果程序员需要重用文件流读写多个文件,必须在读另一个文件之前调用 clear 清除该流的状态。
文件打开的模式有:
in 打开文件做读操作
out 打开文件做写操作
app 在每次写之前找到文件尾
ate 打开文件后立即将文件定位在文件尾
trunc 打开文件时清空已存在的文件流
binary 以二进制模式进行 IO 操作
如:ofstream appfile("file2", ofstream::app);
outfile.open("scratchpad", ofstream::out);
7. 字符串流的常见用法是什么?
string line, word;
while (getline(cin, line))
{
istringstream stream(line);
while (stream >> word)
{
// do per-word processin
}
}