ofstream的close方法也会关闭基础句柄吗

时间:2018-10-11 02:38:35

标签: c++ windows iostream

在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的构造函数的人,实际上是see the screen shot below

1 个答案:

答案 0 :(得分:2)

我希望您已经知道您正在使用的构造函数:

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也会关闭文件描述符

(我的重点。)