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()?
更新:对于那些说没有 ofstream 获取 FILE* 的构造函数的人,实际上有,有点,
我希望您已经知道您正在使用的构造函数:
std::ofstream(FILE * fp)
是一个非标准的、未记录的 Microsoft 扩展,甚至 Microsoft 也不保证。
在那种情况下,Microsoft 甚至不会向您承诺:
int fd = ...;
...
FILE * fp = _fdopen(fd, "w");
...
std::osftream ofs(fp);
...
ofs.close();
会做 fclose(fp)
- 没关系 _close(fd)
.
但是,如果您认为 ofs.close()
会 fclose(fp)
- 显然您会 - 那么 Microsoft
确实向您保证它也会 _close(fd)
。来自 the documentation
Remarks
...
File descriptors passed into _fdopen are owned by the returned FILE * stream.
If _fdopen is successful, do not call _close on the file descriptor.
Calling fclose on the returned FILE * also closes the file descriptor.
(我的重点。)
在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()?
更新:对于那些说没有 ofstream 获取 FILE* 的构造函数的人,实际上有,有点,
我希望您已经知道您正在使用的构造函数:
std::ofstream(FILE * fp)
是一个非标准的、未记录的 Microsoft 扩展,甚至 Microsoft 也不保证。
在那种情况下,Microsoft 甚至不会向您承诺:
int fd = ...;
...
FILE * fp = _fdopen(fd, "w");
...
std::osftream ofs(fp);
...
ofs.close();
会做 fclose(fp)
- 没关系 _close(fd)
.
但是,如果您认为 ofs.close()
会 fclose(fp)
- 显然您会 - 那么 Microsoft
确实向您保证它也会 _close(fd)
。来自 the documentation
Remarks
...
File descriptors passed into _fdopen are owned by the returned FILE * stream. If _fdopen is successful, do not call _close on the file descriptor. Calling fclose on the returned FILE * also closes the file descriptor.
(我的重点。)