头文件 fstream 定义了三个类型来支持文件IO:
ifstream
从一个给定文件读取数据。ofstream
向一个文件写入数据。fstream
可以读写给定的文件。
这些操作可以使用 IO
运算符(<<和>>)来读写文件,可以使用 getline
从一个 ifstream
读取数据。
使用文件流对象
如果想要读写一个文件,可以定义一个文件流对象,并将对象与文件关联起来。每个文件流类都定义了一个名为open
的成员函数,它完成一些系统操作相关的工作,来定位给定的文件,并视情况打开为读或写模式。
创建流对象时,如果提供了文件名,则 open
函数自动被调用。
C++ 标准中,文件名既可以是 string
类型,也可以是C风格字符串。
ifstream in(infile); //构造一个ifsytream并打开给定的文件
ostream out; //输出文件流并未关联任何文件
用fstream 代替 iostream&
在要求使用基类型对象的地方,可以用继承类型的对象来代替。所以,接受一个 iostream
类型引用或指针参数的函数可以用一个对应的 fstream
或 sstream
类型来调用。也就是说,对于一个接受 ostream&
参数的函数,调用这个函数时可以传递给它一个 ofstream
对象,对于 istream
和 ifstream
也是类似的。
成员函数open 和 close
如果定义了一个空的文件流对象,可以随后调用 open
来将其与文件关联。
ifstream in(infile);
ostream out;
out.open(infile + ".copy");
如果 open
调用失败, failbit
将会被置位,因为调用 open
可能失败,所以进行 open
是否成功的检测通常是一个好的习惯:
if(out) //检查open是否成功
//open成功,继续其它操作
如果 open 成功,则open会设置流的状态,使得 good() 为true。
一旦一个流已经打开,它就会保持与对应文件的关联。对一个打开的文件流调用 open将会失败,并会导致failbit被置位。随后试图使用这个文件流的操作都会失败,为了将文件流关联到另一个文件,首先需要关闭已经关联的流,一旦文件关闭成功,可以重新打开新的文件。
in.close(); //关闭文件
in.open(infile + "2"); //打开另一个文件
自动构造和析构
考虑使用main函数接受一个要处理的文件列表:
for (auto p = argc + 1; p != argv + argc; ++p)
{
ifstream input(*p); //创建输入流并打开文件
if (input) //判断文件是否打开成功
{
process(input); //处理文件
}
else
{
cerr << "could not open" << string(*p) << endl;
}
}
上面的每个循环都会构造一个新的名为 input
的 ifstream
对象,并打开它来读取给定的文件。
检查文件是否打开成功,如果成功则调用处理函数。如果失败,则打印一条错误信息并继续处理下一个文件。
input
是 while
循环的局部变量,它在每个循环步中都要创建和销毁一次,当一个 fstream
对象离开其作用域时,与之关联的文件会自动关闭。
文件模式
每个流都有一个关联的文件模式,用来指出如何使用文件。
无论使用哪种方式打开文件,都可以指定文件模式,调用 open
打开文件时可以,用一个文件名初始化流来隐式打开文件时也可以。
指定文件模式有如下限制:
- 只可以对
ofstream
或fstream
对象设定out
模式。 - 只可以对
ifstream
或fstream
对象设定in
模式。 - 只有当
out
也被设定时才可以设定trunc
模式。 - 只要
trunc
没有被设定,就可以设定app
模式,在app
模式下,即使没有显示指定out
模式,文件也总是以输出的方式被打开。 - 默认情况下,即使没有指定
trunc
,以out
模式打开的文件也会被截断,为了保留以out
模式打开的文件的内容,我们必须同时指定app
模式,这样只会将数据追加写到文件末尾,或者同时指定in
模式,即打开文件同时进行读写。 ate
和binary
模式可以用于任何类型的文件流,且可以与其他任何文件模式组合使用。- 每个文件流类型都定义了一个默认的文件模式:
ifstream
关联的文件默认使用in
模式打开。ofstream
关联的文件默认使用out
模式打开。fstream
关联的文件默认以in
和out
模式打开。
以 out 模式打开的文件会丢失已有数据
默认情况下,当打开一个 ofstream
时,文件的内容会被丢弃,阻止一个 ofstream
清空给定文件内容的方法是同时指定 app
模式:
//下面的语句中file1都被截断
ofstream out("file1"); //隐含以输出模式打开截断文件
ofstream out("file1",ofstream::out); //隐含地截断文件
ofstream out("file1", ofstream::out | ofstream::trunc);
//为了保留文件内容,必须显示地指定app模式
ofstream out("file1", ofstream::app); //隐含为输出模式
ofstream out("file1", ofstream::out | ofstream::app);
注意:
保留 ofstream
打开的文件中已有数据的唯一方法是显示制定 app
或 in
模式。
每次调用open时都会确定文件模式
对于一个给定的流,每当打开文件时,都可以改变其文件模式。
ofstream out; //未指定文件打开
out.open("file1"); //模式隐含设置为输出和截断
out.close(); //关闭out,以便将其用于其他文件
out.open("file2", ostream::app); //模式为输出和追加
out.close();
每次打开文件时,都要设置文件模式,可能是显示的设置,也可能是隐式地设置,当程序未指定模式时,就使用默认值。