游戏开发工具

C++打开的文件一定要用close()方法关闭!

通过前面的学习我们知道,C++ 使用 open() 方法打开文件,使用 close() 方法关闭文件。例如(程序一):

#include <iostream>     //std::cout
#include <fstream>        //std::ofstream
using namespace std;

int main()
{
    const char * url = "http://www.gamecolg.com/cplus/";
    //以文本模式打开out.txt
    ofstream destFile("out.txt", ios::out);
    if (!destFile) 
    {
        cout << "文件打开失败" << endl;
        return 0;
    }
    //向out.txt文件中写入 url 字符串
    destFile << url;
    //关闭打开的 out.txt 文件
    destFile.close();
    return 0;
}

执行该程序,会生成一个 out.txt 文件,内部存有如下内容:

http://www.gamecolg.com/cplus/

前面提到,在某些情况下(例如上面程序中),即便不显式调用 close() 方法,文件的读写操作也能成功执行。因为当文件流对象的生命周期结束时,会自行调用析构函数,此函数内部会先调用 close() 方法切断文件流对象与任何文件的关联,最后才销毁它。

那么,既然文件流对象自行销毁时会隐式调用 close() 方法,是不是就不用显式调用 close() 方法了呢?

当然不是,在实际进行文件操作的过程中,对于打开的文件,要及时调用 close() 方法将其关闭,否则很可能会导致读写文件失败。

举个例子(程序二):

#include <iostream>     //std::cout
#include <fstream>      //std::ofstream
using namespace std;

int main()
{
    const char * url = "http://www.gamecolg.com/cplus/";
    //以文本模式打开out.txt
    ofstream destFile("out.txt", ios::out);
    if (!destFile) 
    {
        cout << "文件打开失败" << endl;
        return 0;
    }
    //向out.txt文件中写入 url 字符串
    destFile << url;
    //程序抛出一个异常
    throw "Exception";
    //关闭打开的 out.txt 文件
    destFile.close();
    return 0;
}

通过对比不难发现,此程序和程序一唯一的区别在于,第 17 行添加了抛出异常的语句。由于程序中没有对抛出的异常进行处理,因此当程序执行到此行时会崩溃。

更重要的是,第 17 行会导致文件写入操作失败。执行此程序,同样会生成 out.txt 文件,但 "http:www.gamecolg.com/cplus/" 字符串并没有成功被写入。

也就是说,对于已经打开的文件,如果不及时关闭,一旦程序出现异常,则很可能会导致之前读写文件的所有操作失效。在程序二的基础上,如果将第 17 行代码和第 19 行代码互换,再次执行程序会发现,虽然程序执行仍会崩溃,但 "http:www.gamecolg.com/cplus/" 字符串可以被成功写入到 out.txt 文件中。

C++ flush()刷新缓冲区

在很多实际场景中,即便已经对文件执行了写操作,但后续还可能会执行其他的写操作。对于这种情况,我们可能并不想频繁地打开/关闭文件,可以使用 flush() 方法及时刷新输出流缓冲区,也能起到防止写入文件失败的作用。

程序二之所以写入文件失败,是因为 << 写入运算符会先将 url 字符串写入到输出流缓冲区中,待缓冲区满或者关闭文件时,数据才会由缓冲区写入到文件中。但直到程序崩溃,close() 方法也没有得到执行,且 destFile 对象也没有正常销毁,所以 url 字符串一直存储在缓冲区中,没有写入到文件中。

比如,修改程序二的代码:

#include <iostream>     //std::cout
#include <fstream>      //std::ofstream
using namespace std;

int main()
{
    const char * url = "http://www.gamecolg.com/cplus/";
    //以文本模式打开out.txt
    ofstream destFile("out.txt", ios::out);
    if (!destFile) 
    {
        cout << "文件打开失败" << endl;
        return 0;
    }
    //向out.txt文件中写入 url 字符串
    destFile << url;
    //程序抛出一个异常
    throw "Exception";
    //关闭打开的 out.txt 文件
    destFile.close();
    return 0;
}

可以看到,在程序二的基础上,在第 17 行调用了 flush() 方法。再次执行程序,虽然仍执行崩溃,但 "http://c.baincheng.net/cplus/" 字符串成功写入到了 out.txt 文件中。

总之,C++ 中使用 open() 打开的文件,在读写操作执行完毕后,应及时调用 close() 方法关闭文件,或者对文件执行写操作后及时调用 flush() 方法刷新输出流缓冲区。