第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 值,则该函数返回 true

s.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

    }
}

posted @ 2014-04-22 15:33  蓝蓝鱼鱼  阅读(242)  评论(0编辑  收藏  举报