在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()?
更新:对于那些说没有采用FILE *的ofstream的构造函数的人,实际上是
最佳答案
我希望您已经知道您正在使用的构造函数:
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备注
...
传递到_fdopen的文件描述符由返回的FILE *流拥有。
如果_fdopen成功,则不要在文件描述符上调用_close。
在返回的FILE *上调用fclose也会关闭文件描述符。
(我的重点。)