C++ close()关闭文件的重要性
通过前面的学习我们知道,C++ 使用 open() 方法打开文件,使用 close() 方法关闭文件。例如(程序一):
前面提到,在某些情况下(例如上面程序中),即便不显式调用 close() 方法,文件的读写操作也能成功执行。因为当文件流对象的生命周期结束时,会自行调用析构函数,此函数内部会先调用 close() 方法切断文件流对象与任何文件的关联,最后才销毁它。
那么,既然文件流对象自行销毁时会隐式调用 close() 方法,是不是就不用显式调用 close() 方法了呢?
当然不是。在实际进行文件操作的过程中,对于打开的文件,要及时调用 close() 方法将其关闭,否则很可能会导致读写文件失败。
举个例子(程序二):
更重要的是,第 17 行会导致文件写入操作失败。执行此程序,同样会生成 out.txt 文件,但 "http:www.xinbaoku.com/cplus/" 字符串并没有成功被写入。
也就是说,对于已经打开的文件,如果不及时关闭,一旦程序出现异常,则很可能会导致之前读写文件的所有操作失效。在程序二的基础上,如果将第 17 行代码和第 19 行代码互换,再次执行程序会发现,虽然程序执行仍会崩溃,但 "http:www.xinbaoku.com/cplus/" 字符串可以被成功写入到 out.txt 文件中。
程序二之所以写入文件失败,是因为 << 写入运算符会先将 url 字符串写入到输出流缓冲区中,待缓冲区满或者关闭文件时,数据才会由缓冲区写入到文件中。但直到程序崩溃,close() 方法也没有得到执行,且 destFile 对象也没有正常销毁,所以 url 字符串一直存储在缓冲区中,没有写入到文件中。
比如,修改程序二的代码:
总之,C++ 中使用 open() 打开的文件,在读写操作执行完毕后,应及时调用 close() 方法关闭文件,或者对文件执行写操作后及时调用 flush() 方法刷新输出流缓冲区。
#include <iostream> //std::cout #include <fstream> //std::ofstream using namespace std; int main() { const char * url = "https://www.xinbaoku.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 文件,内部存有如下内容:
https://www.xinbaoku.com/cplus/
前面提到,在某些情况下(例如上面程序中),即便不显式调用 close() 方法,文件的读写操作也能成功执行。因为当文件流对象的生命周期结束时,会自行调用析构函数,此函数内部会先调用 close() 方法切断文件流对象与任何文件的关联,最后才销毁它。
那么,既然文件流对象自行销毁时会隐式调用 close() 方法,是不是就不用显式调用 close() 方法了呢?
当然不是。在实际进行文件操作的过程中,对于打开的文件,要及时调用 close() 方法将其关闭,否则很可能会导致读写文件失败。
举个例子(程序二):
#include <iostream> //std::cout #include <fstream> //std::ofstream using namespace std; int main() { const char * url = "https://www.xinbaoku.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.xinbaoku.com/cplus/" 字符串并没有成功被写入。
也就是说,对于已经打开的文件,如果不及时关闭,一旦程序出现异常,则很可能会导致之前读写文件的所有操作失效。在程序二的基础上,如果将第 17 行代码和第 19 行代码互换,再次执行程序会发现,虽然程序执行仍会崩溃,但 "http:www.xinbaoku.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 = "https://www.xinbaoku.com/cplus/"; //以文本模式打开out.txt ofstream destFile("out.txt", ios::out); if (!destFile) { cout << "文件打开失败" << endl; return 0; } //向out.txt文件中写入 url 字符串 destFile << url; //刷新输出流缓冲区 destFile.flush(); //程序抛出一个异常 throw "Exception"; //关闭打开的 out.txt 文件 destFile.close(); return 0; }可以看到,在程序二的基础上,在第 17 行调用了 flush() 方法。再次执行程序,虽然仍执行崩溃,但 "http://c.baincheng.net/cplus/" 字符串成功写入到了 out.txt 文件中。
总之,C++ 中使用 open() 打开的文件,在读写操作执行完毕后,应及时调用 close() 方法关闭文件,或者对文件执行写操作后及时调用 flush() 方法刷新输出流缓冲区。
所有教程
- C语言入门
- C语言编译器
- C语言项目案例
- 数据结构
- C++
- STL
- C++11
- socket
- GCC
- GDB
- Makefile
- OpenCV
- Qt教程
- Unity 3D
- UE4
- 游戏引擎
- Python
- Python并发编程
- TensorFlow
- Django
- NumPy
- Linux
- Shell
- Java教程
- 设计模式
- Java Swing
- Servlet
- JSP教程
- Struts2
- Maven
- Spring
- Spring MVC
- Spring Boot
- Spring Cloud
- Hibernate
- Mybatis
- MySQL教程
- MySQL函数
- NoSQL
- Redis
- MongoDB
- HBase
- Go语言
- C#
- MATLAB
- JavaScript
- Bootstrap
- HTML
- CSS教程
- PHP
- 汇编语言
- TCP/IP
- vi命令
- Android教程
- 区块链
- Docker
- 大数据
- 云计算