Can I use CreateFile, but force the handle into a std::ofstream?
Asked Answered
S

2

21

Is there any way to take advantage of the file creation flags in the Win32 API such as FILE_FLAG_DELETE_ON_CLOSE or FILE_FLAG_WRITE_THROUGH as described here http://msdn.microsoft.com/en-us/library/aa363858(VS.85).aspx , but then force that handle into a std::ofstream?

The interface to ofstream is obviously platform independent; I'd like to force some platform dependent settings in 'under the hood' as it were.

Superinduce answered 24/1, 2009 at 10:50 Comment(0)
I
31

It is possible to attach a C++ std::ofstream to a Windows file handle. The following code works in VS2008:

HANDLE file_handle = CreateFile(
    file_name, GENERIC_WRITE,
    0, NULL, CREATE_ALWAYS,
    FILE_ATTRIBUTE_NORMAL, NULL);

if (file_handle != INVALID_HANDLE_VALUE) {
    int file_descriptor = _open_osfhandle((intptr_t)file_handle, 0);

    if (file_descriptor != -1) {
        FILE* file = _fdopen(file_descriptor, "w");

        if (file != NULL) {
            std::ofstream stream(file);

            stream << "Hello World\n";

            // Closes stream, file, file_descriptor, and file_handle.
            stream.close();

            file = NULL;
            file_descriptor = -1;
            file_handle = INVALID_HANDLE_VALUE;
        }
}

This works with FILE_FLAG_DELETE_ON_CLOSE, but FILE_FLAG_WRITE_THROUGH may not have the desired effect, as data will be buffered by the std::ofstream object, and not be written directly to disk. Any data in the buffer will be flushed to the OS when stream.close() is called, however.

Insolvable answered 24/1, 2009 at 13:24 Comment(3)
Excellent (also works in VS2005)! One scenario I have is for writing some accounting information to a file on a USB with write-through. Because it'll be a quick open-write-close sequence, the call to close should ensure ofstream's buffer is flushed to the OS, right?Superinduce
Any idea on how to do the same for fstream instead of ofstream?Greig
I've just tried this in VS2015 and it works with one important caveat. When using the undocumented constructor std::ofstream(FILE*), you have to call ofstream::close() explicitly to close the file. The destructor of the ofstream object will not close it.Unchartered
R
2

Some of these flags are also available when using _fsopen / fopen:

FILE* pLockFile = _fsopen(tmpfilename.c_str(), "w", _SH_DENYWR );
if (pLockFile!=NULL
{
   // Write lock aquired
   ofstream fs(pLockFile);
}

Here we open the file so when doing a flush, then it writes through (And it is deleted when closed):

FILE* pCommitFile = fopen(tmpfilename.c_str(), "wcD");
if (pCommitFile!=NULL)
{
   // Commits when doing flush
   ofstream fs(pCommitFile);
}
Retention answered 23/6, 2010 at 12:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.