C++ ofstream的close方法是否也会关闭底层句柄

C++ ofstream的close方法是否也会关闭底层句柄,c++,windows,iostream,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_writ

在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;
}
#包括“stdafx.h”
#包括
#包括
#包括
#包括
#包括
#包括
类CSV_编写器{
公众:
std::流我的流;
私人:
HANDLE my\u HANDLE=无效的\u HANDLE\u值;
int file_描述符=-1;
FILE*my_FILE=nullptr;//文件类型实际上是一个IO buff。
常量静态无符号整数fl=256;
公众:
显式CSV_写入程序(常量TCHAR*文件名){
//获取当前目录
TCHAR当前路径[最大路径];
GetCurrentDirectory(最大路径、当前路径);
TCHAR文件名[fl]{0};
_tcscat(文件名、文件名);
_tcscat_s(文件名,_T(“.csv”);
如果(当前路径)[u tcslen(当前路径)-1]!=\u T('\\')&&&u tcslen(当前路径)我的句柄=创建文件(
当前路径,
GENERIC_READ | GENERIC_WRITE,//访问许可,读和写
0,//无法共享,并且在关闭文件或设备的句柄之前无法再次打开
nullptr,//返回的句柄不能被子进程继承
CREATE_ALWAYS,//始终创建新文件,如果旧文件存在,则覆盖它
文件\u属性\u正常,
nullptr
);
if(my_handle!=无效的_handle_值){
int file_descriptor=_open_osfhandle((intptr_t)my_handle,_O_TEXT);
如果(文件描述符!=-1){
这->我的文件=_fdopen(文件描述符,“w”);
如果(此->我的文件!=nullptr){
this->my_of stream=std::of stream(this->my_文件);
}
}
}
}
~CSV_writer(){
//关闭流、文件、文件描述符和文件句柄。
这->我的流的u.flush();
这->我的流的u.close();
这->我的文件=nullptr;
这个->文件\描述符=-1;
此->我的\u句柄=无效的\u句柄\u值;
}
};
int main(int argc,char*argv[])
{
CSV_writer CSV_writer(L“内存布局”);

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

std::ofstream(FILE * fp)
是一个非标准的、未记录的Microsoft扩展,甚至没有Microsoft的担保

在这种情况下,Microsoft甚至不向您承诺:

int fd = ...;
...
FILE * fp = _fdopen(fd, "w");
...
std::osftream ofs(fp);
...
ofs.close();
将执行
fclose(fp)
-不要管
\u close(fd)

然而,如果你认为ofs.close()的
确实是
fclose(fp)
——显然你是这样认为的——那么微软 是否向您承诺它也将从中关闭(fd)

评论

传递到_fdopen的文件描述符归返回的文件*流所有。 如果_fdopen成功,不要调用文件描述符上的_close对返回的文件*调用fclose也会关闭文件描述符


(我的重点。)

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

std::ofstream(FILE * fp)
是一个非标准的、未记录的Microsoft扩展,甚至没有Microsoft的担保

在这种情况下,Microsoft甚至不向您承诺:

int fd = ...;
...
FILE * fp = _fdopen(fd, "w");
...
std::osftream ofs(fp);
...
ofs.close();
将执行
fclose(fp)
-不要管
\u close(fd)

然而,如果你认为ofs.close()的
确实是
fclose(fp)
——显然你是这样认为的——那么微软 是否向您承诺它也将从中关闭(fd)

评论

传递到_fdopen的文件描述符归返回的文件*流所有。 如果_fdopen成功,不要调用文件描述符上的_close对返回的文件*调用fclose也会关闭文件描述符


(我的重点。)

有一个
std::ofstream
的构造函数,它接受一个
文件*
参数?@Steve我找不到这样的构造函数,甚至找不到Microsoft特定的构造函数。除非有,否则这个问题毫无意义,因为你无论如何都无法以这种方式打开一个。你能发布一个人们可以帮助你的构造函数吗?不要将代码作为链接发布。将代码作为文本发布。有一个
std::ofstream
的构造函数,它接受一个
文件*
参数?@Steve我找不到这样的构造函数,甚至找不到Microsoft特定的构造函数。除非有,否则这个问题毫无意义,因为你无论如何都无法打开一个。你能发布一个人们可以帮助你的构造函数吗?不要将代码作为链接发布。将代码作为文本发布。Nice文档挖掘。我的理由是MS添加扩展是有原因的,因此不需要在创建句柄后首先关闭句柄,然后使用其路径打开它来处理它。我敢打赌,在iostream实例被销毁后,句柄会关闭。@JohnZ.Li我确信它和实验会确认它,但pe通常我还是不会让重要的代码依赖于未记录的扩展。很好的文档挖掘。我的理由是MS添加扩展是有原因的,这样就不需要在创建句柄后首先关闭句柄,然后使用其路径打开它来处理它。我敢打赌,句柄在iostream instanc之后关闭e被销毁。@JohnZ.Li我相信它和实验会证实这一点,但就我个人而言,我仍然不会让重要的代码依赖于未记录的扩展。