IO 类
IO 库类型和头文件
iostream 定义了用于读写流的基本类型,fstream 定义了读写命名文件的类型,sstream 定义了读写内存 string 对象的类型。
其中带 w 前缀的类型用来操作宽字符语言 (wchar_t)。宽字符版本的类型和函数前都有一个 w,如 wcin, wcout, wcerr。
可以将一个派生类(继承类)对象当成基类(所继承的类)对象来使用。
IO对象无拷贝或赋值
ofstream out1,out2;
out1 =out2;//错误:不能对流对象赋值
ofstream print(ofstream);//错误:不能初始化ofstream参数
out2 = print(out2);//错误:不能拷贝流对象
不能拷贝或对 IO 对象赋值,因此也不能将形参或返回类型设置成流类型。
进行 IO 操作的函数通常以引用形式传递和返回流。读写 IO 对象会改变其状态,因此传递和返回的引用不能是 const 的。
条件状态
条件状态用来查看流的状态。
IO 库的状态
strm::iostate//strm是一种IO类型。iostate是一种机器相关的类型,提供了表达条件状态的完整功能。
strm::badbit//strnm::badbit用来指出流已崩溃
strn::failbit//sirm::failbit用来指出一个IO操作失败了
strm::eofbit//strm::eofbit用来指出流到达了文件结束
strm::goodbit//strm::goodbit用来指出流未处于错误状态。此值保证为零.
流的状态
//查询
s.eof()//若流s的eofbit置位,则返回true
s.fail()//若流s的failbit或badbit置位,则返回 true
s.bad()//若流s的badbit置位,则返回true
s.good()//若流s处于有效状态,则返回true
//管理
s.clear()//将流s中所有条件状态位复位,将流的状态设置为有效.返回void
s.clear(flags)//根据给定的flags标志位,将流s中对应条件状态位复位。flags的类型为strm::iostate。返回void
s.setstate(flags)//根据给定的flags标志位,将流s中对应条件状态位置位。flags的类型为strm::iostate.返回void
s.rdstate() //返回流s的当前条件状态,返回值类型为strm::iostate
管理输出缓冲
操作系统可以通过缓冲机制将程序的多个输出操作组合成单一的系统级写操作。
缓冲刷新的原因:
1.程序正常结束,作为 main 函数的 return 操作的一部分,缓冲刷新被执行;
2.缓冲区满时,需要刷新缓冲,而后新的数据才能继续写入缓冲区;
3.可以使用操纵符如 endl 来显式刷新缓冲区;
4.在每个输出操作之后,可以用操纵符 unitbuf 设置流的内部状态,来清空缓冲区。默认情况下,对 cerr是设置 unitbuf 的,因此写到 cerr 的内容都是立即刷新的,不缓冲的。
5.一个输出流可能被关联到另一个流。在这种情况下,当读写被关联的流时,关联到的流的缓冲区会被刷新。例如,默认情况下,cin 和 cerr都关联到cout。因此,读cin或写cerr都会导致cout的缓冲区被刷新。
IO库中三个显式刷新缓冲区的操作符:
cout<< "hi!" <<endl;//输出hi和一个换行,然后刷新缓冲区
cout<< "hi!" <<flush;//输出hi,然后刷新缓冲区,不附加任何额外字符
cout<< "hi!" <<ends;//输出hi和一个空字符,然后刷新缓冲区
unitbuf 操作符:告诉流在接下来的每次写操作之后进行一次 flush 操作。
nounitbuf 操作符:重置流,使其恢复使用正常的系统管理的缓冲区刷新机制。
cout << unitbuf;//所有输出操作后都会立即刷新缓冲区
//任何输出都立即刷新,无缓冲
cout << nounitbuf;//回到正常的缓冲方式
如果程序崩溃,输出缓冲区不会被刷新,即此时相应的输出操作已执行但没有打印。
当一个输入流被关联到一个输出流时,任何试图从输入流读取数据的操作都会先刷新关联的输出流。
// cout 和 cin 关联在一起
cin >> ival;//语句执行会导致 cout 的缓冲区被刷新。
输入流的成员函数 tie 可以用来查看关联的输出流或关联到输出流:
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 特有的操作:
使用文件流对象
//创建文件流对象时,提供了一个文件名,则 open 会自动被调用
ifstream in(ifile);//构造一个ifstream并打开给定文件
ofstream out;//输出文件流未关联到任何文件
接受一个 iostream 类型引用(或指针)参数的函数,可以用一个对应的 fstream(或 sstream)类类型来调用。
成员函数 open 和 close
如果定义了一个空文件流对象,可以随后调用 ope n来将它与文件关联起来:
ifstream in(ifile);//构筑一个ifstream并打开给定文件
ofstream out;//输出文件流未与任何文件相关联
out.open (ifile+ ".copy" );//打开指定文件
if(out)//检查 open 是否成功
一旦一个文件流已经打开,它就保持与对应文件的关联。对一个已经打开的文件流调用 open 会失败,并导致 failbit 被置位。
为了将文件流关联到另外一个文件,必须首先关闭已经关联的文件:
in.close();//关闭文件
in.open(ifile +"2");//打开另一个文件
当一个 fstream 对象被销毁时,close会自动被调用。
文件模式
每个流都有一个关联的文件模式,用来指出如何使用文件。
指定文件模式的限制:
1.ifstream 默认 in 模式打开文件,ofstream 默认 out,fstream 默认 in 或 out。只可以对 ofstream 或 fstream 对象设定 out 模式。只可以对 ifstream 或 fstream 对象设定 in 模式。
2.只有当 out 也被设定时才可设定 trunc 模式,通常情况下 out 模式意味着同时使用 trunc 模式。
3.只要 trunc 没被设定,就可以设定 app 模式。在 app 模式下,即使没有显式指定 out 模式,文件也总是以输出方式被打开。
4.默认情况下,即使我们没有指定 trunc,以 out 模式打开的文件也会被截断。以 out模式打开文件会丢弃已有数据,保留被 ofstream打开的文件中已有数据的唯一方法是显式指定app或in模式。
5.ate 和 binary 模式可用于任何类型的文件流对象,且可以与其他任何文件模式组合使用。
string 流
三个类型:istringstream 从 string读取数据,ostringstream向string 写入数据,而头文件 stringstream既可从 string 读数据也可向string写数据。
istringstream 是输入流,即读操作,要将流中的内容输入到字符串中,因此定义和使用 istringstream 时流内必须有内容,所以在使用前要提前在流内保存一个字符串。
ostringstream 是输出流,即写操作,将流中的内容输出到字符串中,ostringstream 可以在定义时即在流中保存一个字符串,也可以通过 << 操作符获得字符串。
重要术语
条件状态(condition state) 可被任何流类使用的一组标志和函数,用来指出给定流是否可用。
文件模式(file mode) 类fstream定义的一组标志,在打开文件时指定,用来控制文件如何被使用。
文件流(file stream) 用来读写命名文件的流对象。除了普通的 iostream 操作,文件流还定义了open 和 close 成员。成员函数 open 接受一个 string 或一个C风格字符串参数,指定要打开的文件名,它还可以接受一个可选的参数,指明文件打开模式。成员函数 close 关闭流所关联的文件,调用 close 后才可以调用 open 打开另一个文件。