- iostream定义了用于读写流的基本类型,fstream定义了读写命名文件的类型,sstream定义了读写内存string对象的类型。
- 标准库使咱们能忽略这些不一样类型的流之间的差别,这是经过继承机制实现的。
- 因为不能拷贝IO对象,所以咱们也不能将形参或返回类型设置为流类型。进行IO操做的函数一般以引用方式传递和返回流。读写一个IO对象会改变其状态,所以传递和返回的引用不能是const的
- IO库条件状态
状态 |
解释 |
strm::iostate |
strm是一种IO类型,iostate是一种机器相关的类型,提供了表达条件状态的完整功能。IO库定义了4个iostate类型的constexpr值,表示特定的位模式。 |
strm::badbit |
二进制值为100,用来指出流已崩溃 |
strm::failbit |
二进制值为010,用来指出一个IO操做失败了 |
strm::eofbit |
二进制值为001,用来指出流已到达了文件结束 |
strm::goodbit |
用来指出流未处于错误状态。此值保证为零 |
s.eof() |
若流s的eofbit置位(置1),则返回true |
s.fail() |
若流s的failbit或badbit置位,则返回true |
s.bad() |
若流s的badbit置位,则返回true |
s.good() |
若流s处于有效状态,则返回true |
s.clear() |
将流s中全部条件状态位复位(置0),将流的状态设置为有效。返回void |
s.clear(flags) |
根据给定的flags标志位,将流s中对应条件状态位置位。flags的类型为strm::iostate。返回void |
s.setstate(flags) |
根据给定的flags标志位,将流s中对应条件状态位置位。flags的类型为strm::iostate。返回void |
s.rdstate() |
返回流s的当前条件状态,返回值类型为strm::iostate |
#include<iostream>
#include<string>
using namespace std;
istream& func(istream& is)
{
int v;
while (is >> v, !is.eof()) // 直到遇到文件结束符才中止读取
{
if (is.bad())
{
cerr << "Bad Error!\n";
break;
}
else if (is.fail())
{
cerr << "Wrong Data! Please try again!\n";
is.clear();
is.ignore(1024, '\n');
continue;
}
cout << v << endl;
}
is.clear();
return is;
}
int main()
{
func(cin);
return 0;
}
- badbit表示系统级错误,如不可恢复的读写错误。一般状况下,一旦badbit被置位,流就没法再使用了。在发生可恢复错误后,failbit被置位,如指望读取数值却读出一个字符等错误。这种问题一般是能够修正的,流还能够继续使用。若是到达文件结束位置,eofbit和failbit都会被置位。goodbit的值为0,表示流未发生错误。若是badbit、failbit和eofbit任一个被置位,则检测流状态的条件会失败。
- 在badbit被置位时,fail也会返回true。这意味着,使用good或fail是肯定流的整体状态的正确方法。实际上,咱们将流看成条件使用的代码就等价于
!fail()
。而eof和bad操做只能表示特定的错误。
- 下面的代码将
failbit
和badbit
复位,但保持eofbit
不变:// 复位failbit和badbit,保持其余标志位不变
cin.clear(cin.rdstate() & ~cin.failbit & ~cin.badbit);
/*
* clear和setstate的区别:
* clear用实参值强制覆盖当前流的条件状态(不管是0仍是1)
* setstate将实参值(置1的位)叠加到当前流的条件状态
*/
- 致使缓冲刷新的缘由:
- 程序正常结束,做为main函数的return操做的一部分,缓冲刷新被执行。
- 缓冲区满时,须要刷新缓冲,然后新的数据才能继续写入缓冲区。
- 咱们可使用操纵符endl来显式刷新缓冲区
- 在每一个输出操做以后,咱们能够用操纵符unitbuf设置流的内部状态,来清空缓冲区。默认状况下,对cerr是设置unitbuf的,所以写到cerr的内容都是当即刷新的。
- 一个输出流可能被关联到另外一个流。在这种状况下,当读写被关联的流时,关联到的流的缓冲区会被刷新。例如,默认状况下,cin和cerr都关联到cout,所以,读cin或写cerr都会致使cout的缓冲区被刷新。
- 操纵符endl完成换行并刷新缓冲区的工做。flush刷新缓冲区,但不输出任何额外的字符。ends向缓冲区插入一个空字符(
'\0'
),而后刷新缓冲区。
- 若是想在每次输出操做后都刷新缓冲区,咱们可使用unitbuf操纵符。它告诉流在接下来的每次写操做以后都进行一次flush操做。而nounitbuf操纵符则重置流,使其恢复使用正常的系统管理的缓冲区刷新机制:
cout << unitbuf; // 全部输出操做后都会当即刷新缓冲区
// 任何输出都当即刷新,无缓冲
cout << nounitbuf; // 回到正常的缓冲方式
- 若是程序异常终止,输出缓冲区是不会被刷新的。当一个程序崩溃后,它所输出的数据极可能停留在输出缓冲区中等待打印。
- 当一个输入流被关联到一个输出流时,任何试图从输入流读取数据的操做都会先刷新关联的输出流。
- 交互式系统一般应该关联输入流和输出流。这意味着全部输出,包括用户提示信息,都会在读操做以前被打印出来。
- tie有两个重载的版本:一个版本不带参数,返回指向输出流的指针。若是本对象当前关联到一个输出流,则返回的就是指向这个流的指针,若是对象未关联到流,则返回空指针。tie的第二个版本接受一个指向ostream的指针,将本身关连到此ostream,并返回上一个绑定的输出流指针。
- 咱们既能够将一个istream对象关联到另外一个ostream,也能够将一个ostream关联到另外一个ostream。每一个流同时最多关联到一个流,但多个流能够同时关联到同一个ostream
cin.tie(&cout); // 仅仅是用来展现:标准库将cin和cout关联在一块儿
// old_tie指向当前关联到cin的流(若是有的话)
ostream *old_tie = cin.tie(nullptr); // cin再也不与其余流关联
// 将cin与cerr关联;这不是一个好主意,由于cin应该关联到cout
cin.tie(&cerr); // 读取cin会刷新cerr而不是cout
cin.tie(old_tie); // 重建cin和cout间的正常关联
- fstream特有的操做
操做 |
解释 |
fstream fstrm; |
建立一个未绑定的文件流。fstream是头文件fstream中定义的一个类型 |
fstream fstrm(s); |
建立一个fstream,并打开名为s的文件。s能够是string类型,或者是一个指向C风格字符串的指针。这些构造函数都是explicit的。默认的文件模式mode依赖于fstream的类型。 |
fstream fstrm(s, mode); |
与前一个构造函数相似,但按指定mode打开文件 |
fstrm.open(s) |
打开名为s的文件,并将文件与fstrm绑定。s能够是一个string或一个指向C风格字符串的指针。默认的文件mode依赖于fstream的类型。返回void |
fstrm.close() |
关闭与fstrm绑定的文件。返回void |
fstrm.is_open() |
返回一个bool值,指出与fstrm关联的文件是否成功打开且还没有关闭 |
- 在要求使用基类型对象的地方,咱们能够用继承类型的对象来替代。这意味着,接受一个iostream类型引用(或指针)参数的函数,能够用一个对应的fstream(或sstream)类型来调用。
- 若是调用open失败,failbit会被置位。由于调用open可能失败,进行open是否成功的检测一般是一个好习惯。
if (out) // 检查open是否成功
// open成功,咱们可使用文件了
- 一旦一个文件流已经打开,它就保持与对应文件的关联。为了将文件流关联到另一个文件,必须首先关闭已经关联的文件。一旦文件成功关闭,咱们能够打开新的文件。
in.close() // 关闭文件
in.open(ifile + "2"); // 打开另外一个文件
- 当一个fstream对象被销毁时,close会自动被调用。
- 每一个流都有一个关联的文件模式,用来指出如何使用文件。
模式 |
解释 |
in |
以读方式打开 |
out |
以写方式打开 |
app |
每次写操做前均定位到文件末尾 |
ate |
打开文件后当即定位到文件末尾 |
trunc |
截断文件 |
binary |
以二进制方式进行IO |
- 指定文件模式有以下限制:
- 只能够对ofstream或fstream对象设定out模式
- 只能够对ifstream或fstream对象设定in模式
- 只有当out也被设定时才可设定trunc模式
- 只要trunc没被设定,就能够设定app模式。在app模式下,即便没有显式指定out模式,文件也老是以输出方式被打开
- 默认状况下,即便咱们没有指定trunc,以out模式打开的文件也会被截断。为了保留以out模式打开的文件的内容,咱们必须同时指定app模式,这样只会将数据追加写到文件末尾;或者同时指定in模式,即打开文件同时进行读写操做。
- ate和binary模式可用于任何类型的文件流对象,且能够与其余任何文件模式组合使用。
- 保留被ofstream打开的文件中已有数据的惟一方法是显式指定app或in模式
- 在每次打开文件时,都要设置文件模式,多是显式地设置,也多是隐式地设置。当程序未指定模式时,就使用默认值。
- stringstream特有的操做
操做 |
解释 |
sstream strm; |
strm是一个未绑定地stringstream对象。sstream是头文件sstream中定义的一个类型 |
sstream strm(s); |
strm是一个sstream对象,保存string s的一个拷贝。此构造函数是explicit的 |
strm.str() |
返回strm所保存的string的拷贝 |
strm.str(s) |
将string s拷贝到strm中。返回void |
#include<iostream>
#include<sstream>
#include<string>
#include<vector>
using namespace std;
struct PersonInfo
{
string name;
vector<string> phones;
};
int main()
{
string line, word; // 分别保存来自输入的一行和单词
vector<PersonInfo> people; // 保存来自输入的全部记录
istringstream record;
while (getline(cin, line))
{
PersonInfo info; // 建立一个保存此记录数据的对象
record.clear(); // 重复使用字符串流时,每次都要调用clear
record.str(line); // 将记录绑定到刚读入的行
record >> info.name; // 读取名字
while (record >> word) // 读取电话号码
info.phones.push_back(word); // 保持它们
people.push_back(info); // 将此记录追加到people末尾
}
return 0;
}