提问人:John Z. Li 提问时间:10/11/2018 最后编辑:John Z. Li 更新时间:10/11/2018 访问量:214
ofstream 的 close 方法是否也关闭了基础句柄
Does the close method of ofstream also close the underlying handle
问:
在 Windows 平台上,通过调用 CreateFile 获取文件句柄,然后使用该句柄初始化 ofstream 对象。一个最小的例子如下:
#include"stdafx.h"
#include <tchar.h>
#include <iostream>
#include <fstream>
#include <windows.h>
#include <io.h>
#include <fcntl.h>
class CSV_writer {
public:
std::ofstream my_ofstream;
private:
HANDLE my_handle = INVALID_HANDLE_VALUE;
int file_descriptor = -1;
FILE * my_file = nullptr; //FILE type is actually a IO buff.
const static unsigned int fl = 256;
public:
explicit CSV_writer(const TCHAR * file_name_) {
//get current directory
TCHAR current_path[MAX_PATH];
GetCurrentDirectory(MAX_PATH, current_path);
TCHAR filename[fl]{ 0 };
_tcscat_s(filename, file_name_);
_tcscat_s(filename, _T(".csv"));
if (current_path[_tcslen(current_path) - 1] != _T('\\') && _tcslen(current_path) < MAX_PATH - 1) {
_tcscat_s(current_path, _T("\\"));
}
else {
throw std::exception("path length exceeding limit.");
}
if (_tcslen(current_path) + _tcslen(filename) + 1 < MAX_PATH) {
_tcscat_s(current_path, filename);
}
else {
//current path exceeds the max path length defined in MAX_PATH
throw std::exception("path length exceeding limit.");
}
this->my_handle = CreateFile(
current_path,
GENERIC_READ | GENERIC_WRITE, //access permit, both read and write
0, //cannot be shared and cannot be opened again until the handle to the file or device is closed
nullptr, //returned handle can not be inherited by child process
CREATE_ALWAYS, //always create a new file, overwrite old one if it exists
FILE_ATTRIBUTE_NORMAL,
nullptr
);
if (my_handle != INVALID_HANDLE_VALUE) {
int file_descriptor = _open_osfhandle((intptr_t)my_handle, _O_TEXT);
if (file_descriptor != -1) {
this->my_file = _fdopen(file_descriptor, "w");
if (this->my_file != nullptr) {
this->my_ofstream = std::ofstream(this->my_file);
}
}
}
}
~CSV_writer() {
// Closes stream, file, file_descriptor, and file_handle.
this->my_ofstream.flush();
this->my_ofstream.close();
this->my_file = nullptr;
this->file_descriptor = -1;
this->my_handle = INVALID_HANDLE_VALUE;
}
};
int main(int argc, char* argv[])
{
CSV_writer csv_writer(L"memory_layout");
csv_writer.my_ofstream << "Type,\t" << "Size,\t" << "Offset,\t" << "Address\n";
return 0;
}
我的问题是,在之后调用“my_ofstream.close()”之后,底层文件句柄也会被释放吗?还是我必须在调用 close() 后手动调用 Windows API CloseHandle()?
答:
2赞
Mike Kinghan
10/11/2018
#1
我希望你已经知道你正在使用的构造函数:
std::ofstream(FILE * fp)
是一个非标准的、未记录的 Microsoft 扩展,即使是 Microsoft 也无法保证。
在这种情况下,Microsoft甚至不会向您承诺:
int fd = ...;
...
FILE * fp = _fdopen(fd, "w");
...
std::osftream ofs(fp);
...
ofs.close();
会做 - 没关系.fclose(fp)
_close(fd)
但是,如果您认为它确实如此 - 显然您确实如此 - 那么Microsoft
确实向你保证它也会.从文档ofs.close()
fclose(fp)
_close(fd)
言论
...
传递到_fdopen的文件描述符由返回的 FILE * 流拥有。 如果_fdopen成功,请不要对文件描述符调用_close。对返回的 FILE * 调用 fclose 也会关闭文件描述符。
(我的重点。
评论
0赞
John Z. Li
10/11/2018
不错的文件挖掘。我的理由是 MS 添加扩展是有原因的,因此无需在创建句柄后先关闭句柄,然后使用其路径打开它即可使用它。我敢打赌,在 iostream 实例被销毁后,句柄会关闭。
1赞
Mike Kinghan
10/11/2018
@JohnZ.Li 我确信它和实验会证实这一点,但就我个人而言,我仍然不会让重要代码依赖于未记录的扩展。
评论
std::ofstream
FILE*