c++文件流打开模式与is_open方法

闻人修平
2023-12-01

检测流状态的方法


在c++中经常需要读写文件,在打开文件进行操作之前,我们需要确保流的打开状态正常。

可以通过以下方法判断流状态正常:

#include <fstream>

ifstream fin;
fin.open("demo.txt");
// 1st attempt
if (fin.fail()) {} // open failed
// 2nd attempt
if (!fin) {} // open failed
// 3rd attempt
if (!fin.good()) {} // open failed
// 4th attempt
if (!fin.is_open()) {} // open failed

这些方法都是可以的,但是强烈建议使用第4种方法is_open。

因为它能检测出其他方式不能检测到的微妙问题。
——引自《c++ primer plus》

文件打开模式


由于这个微妙问题与文件模式有关,所以在此先做介绍。

文件模式描述的是文件将如何被使用:读、写、追加、二进制方式等。

将流与文件关联时,都可以提供指定文件打开模式的第二个参数:

ifstream fin("bar", mode);// mode指定的模式

c++提供的文件模式如下:

常量含义
ios_base::in以读模式打开文件
ios_base::out以写模式打开文件
ios_base::ate打开文件,并移动到文件尾
ios_base::app追加到文件尾
ios_base::trune如果文件存在,则截短文件
ios_base::binary二进制文件

比如,以追加方式写文件时:

ofstream fout("bar", ios_base::out | ios_base::app);

由于历史原因,c++中经常会有c的代码,或者c++使用c编写的库,所以需要清楚 c++ 与 c 打开模式的对应关系:

c++模式c模式含义
ios_base::in“r”以读模式打开文件
ios_base::out“w”以写模式打开文件,如果文件已存在,则截短文件,同 “ios_base::out | ios_base::trune”
ios_base::out | ios_base::app“a”追加写
ios_base::in | ios_base::out“r+”以读写模式打开,在文件允许位置写入
ios_base::in | ios_base::out | ios_base::trune“w+”以读写模式打开,如果文件已存在,则截短文件
c++mode | ios_base::binarycmode+b以二进制模式打开文件
c++mode | ios_base::atecmode以指定模式打开文件,并移动到文件尾。c中使用独立的函数调用移动到文件尾:fseek(file, 0, SEEK_END)

注意:ios_base::ate 和 ios_base::app
都将文件指针指向文件尾,二者的区别是ios_base::app只允许将数据添加到文件尾,而ios_base::ate将指针放到文件尾。

为什么使用is_open


其实,在上述四种方法中,前三种测试方法是等价的。

但是,它们无法检测出这样的情况: 以不合适的文件模式打开时导致的失败。

比如,当尝试以ios_base::in | ios_base::trune模式打开文件时,这就是不允许的模式组合,导致打开流失败。

is_open()方法用于检测此种故障。

以上是书上的说法,笔者感觉好奇,当以这种模式打开文件时,会出现怎样的错误情况,于是随手写了个测试程序:

#include <iostream>
#include <fstream>

using namespace std;

int main()
{
    ifstream fin("d.txt", ios_base::in | ios_base::trunc);
    if (!fin.good() || !fin || fin.fail())
    {
        cout << "the 3 ways think open file failed\n";
        return 1;
    }
    cout << "the 3 ways don't think open file failed\n";

    if (!fin.is_open())
    {
        cout << "is_open think open file failed\n";
        return 2;
    }
    cout << "the 4th way don't think open file failed\n";

    char ch;
    while (fin.get(ch))
        cout << ch;
    cout << endl;

    fin.clear();
    fin.close();

    return 0;
}

编译测试:

# 先不创建d.txt文件
% ./a.out 
the 3 ways think open file failed

% touch d.txt && echo a > d.txt
% ./a.out 
the 3 ways think open file failed

由此可见,前三种方式也能检测到此种故障。

小结


is_open()是较新的c++引入的方法,它的引入肯定是存在理由的。

上述示例虽然在我的电脑上运行通过,但在其他系统上可能会如书中讲解一致。

总之,既然使用is_open方法没有副作用,只是多写了几个字符,这样能避免某些隐匿的bug,还是非常值得的。

 类似资料: