本文章根据《C++ Primer》总结而来
IO类型在三个独立的头文件中定义:
- iostream定义读写控制窗口的类型
- fstream定义读写已命名文件的类型
- sstream定义读写存储在内存中的string对象
IO对象不可复制或赋值
1、只有支持复制的元素类型可以存储在vector或其他容器里,所以流对象是不能够存储在vector或其他容器里的。
2、形参或返回类型不能为流类型。如果要传递或返回IO对象,则必须传思或返回指向该对象的指针或引用。
所有流对象都包含一个条件状态成员,该成员由setstate和clear操作管理。
badbit标志着系统级的故障,如无法恢复的读写错误。
failbit导致的问题通常是可以修正的。
efobit是在遇到文件结束符时设置的。
检查流状态最简单的方法是检查其真值。
if(cin) {...} //直接检查流状态
while(cin >> word) {...} //检测条件表达式返回的流
每个IO对象管理一个缓冲区,用于存储程序读写的数据。
输出缓冲区的刷新
cout << unitbuf << "first" << "second" << nounitbuf;
等价于
cout << "first" << flush << "second" << flush;
若将输入和输出绑定在一起,则任何读入流的尝试都会首先刷新其输出流相关联的缓冲区。标准库里的cout和cin就是绑在一起的。
fstream头文件定义了三种支持文件IO的类型:
1、ifstream,由istream派生而来,提供读文件的功能。
2、ofstream,由ostream派生而来,提供写文件的功能。
3、fstream,由iostream派生而来,提供读写同一个文件的功能。
fstream定义了自己的新操作——open和close,以及形参为要打开的文件名的构造函数。
需要读写文件时,必须定义自己的对象。
//新建一个ifstream对象并且绑定到文件名为ifile的文件上
ifstream infile(ifile.c_str()); //c_str的使用原因请见下面的引用部分。
//新建一个ofstream对象去写一个名为ofile的文件
ofstream outfile(ofile.c_str());
上述的代码是定义并且打开了一对fstream对象。infile是读的流,outfile是写的流,为ifstream或ofstream对象提供文件名作为初始化式,就相当于打开了特定的文件。
ifstream infile;
ofstream outfile;
上述代码只是定义了一对fstream对象。但因为没有绑定文件,所以无法使用。在使用fstream对象之前,必须使这些对象捆绑要读写的文件。
infile.open("in"); //绑定并打开名为in的文件
outfile.open("out"); //绑定并打开名为out的文件
由于历史原因,IO标准库使用C风格字符串而不是C++的string类型的字符串作为文件名。所以传递文件名的时候实参应该为C风格字符串。假设要使用的文件名保存在string对象中,可以调用c_str成员获取C风格字符串。
打开文件后通常要检查文件是否打开成功,这是一个好习惯。
可以如下检测:
if(!infile) {
cerr << "error: unable to open input file:" << iflile << endl;
return -1;
}
fstream对象一旦打开,就保持与指定的文件相关联。如果要把fstream对象与另一个不同的文件相关联,则必须先关闭现在的文件,然后打开另一个文件。
ifstream infile("in");
infile.close();
infile.open("next");
假设一个vector名为files装有很多文件,我们要对每个文件做一点操作。
vector<string>::const_iterator it = files.begin();
while(it != files.end()) {
ifstream input(it->c_str());
if(!input)
break;
while(input >> s)
process(s);
++it;
}
input是while循环的局部变量,所以每一次循环它都会创建新的input,都是以干净的状态开始使用的,即input.good()为true开始使用。
如果希望避免在每次while循环的过程中创建新的流对象,可将input的定义移到while之前。这点小小的改动意味着必须更加仔细地管理流的状态。如果遇到文件结束符或其他错误,将设置流的内部状态,以便之后不允许再对该流做读写操作。
ifstream input;
vector<string>::const_iterator it = files.begin();
while (it != files.end()) {
input.open(it->c_str());
if(!input)
break;
while (input >> s)
process(s);
input.close();
input.clear();
++it;
}
如果程序员需要重用文件流读写多个文件,必须在读另一个文件之前调用clear清除该流的状态。
打开文件时,无论是调用open还是以文件名作为流初始化的一部分,都需要指定文件模式。
文件模式也是 整型常量,在打开指定文件时,可用位操作符设置一个或多个模式。
默认时,与ofstream关联的文件以out模式打开,使文件可写。以out模式打开的文件会被清空,丢弃该文件存储的所有数据。(相当于同时指定out和trunc模式)
对于用ofstream打开的文件,要保存文件中已存在的数据,唯一的方法是显式地指定app模式打开:
ofstream appfile("file2", ofstream::app);
只要调用open函数,就要设置文件模式,其模式的设置可以是显式地也可以是隐式的。如果没有指定文件模式,就使用默认模式。
默认情况下,fstream对象以in和out模式同时打开。当文件以in和out模式同时打开时不会清空。
fstream inOut("copyOut", fstream::in | fstream::out);