How to Use Createfile, But Force the Handle into a Std::Ofstream

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

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.

Getting a HANDLE from a std::ofstream

The C++ standard does not provide any means for specifying or retrieving the raw file descriptors of an ofstream, so I don't believe this is possible. What is possible, though, would be to build a custom streambuf class that implements stream buffering to and from a HANDLE, then to define a custom ostream type that uses that buffer. I'm not sure if that's really what you're looking for, but it is a viable option.

Force encoding when writing txt file with ofstream

You can call std::ios::imbue on your ofstream object to modify the locale. This won't affect the global locale.

std::ofstream os("output.txt");
std::locale mylocale("");
os.imbue(mylocale);
os << 1.5f << std::endl;
os.close();

Pay attention to the argument of std::locale constructor, it is implementation dependant. For example, the German locale could be :

std::locale mylocale("de_DE"); 

or

std::locale mylocale("German"); 

How to share file delete privilege when I opening a file by ifstream

Visual Studio's version of std::ifstream has a non-standard constructor and a non-standard open() overload that both have an extra optional _Prot parameter for specifying "file protection/sharing flags" (see _fsopen() for the list of available flags). However, delete sharing is not one of supported flags.

There is an alternative, though. Visual Studio's version of both std::ifstream and std::ofstream have non-standard constructors that accept a FILE* for the file access. You can wrap a HANDLE from CreateFile() into a FILE* using Microsoft's _open_osfhandle() and _fdopen() functions, for example (error handling removed for brevity):

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

HANDLE file_handle = CreateFile(...,FILE_SHARE_DELETE,...);
int file_descriptor = _open_osfhandle((intptr_t)file_handle, _O_RDONLY);
FILE* file = _fdopen(file_descriptor, "r");
std::ifstream stream(file);
...
// Closes stream, file, file_descriptor, and file_handle.
stream.close();

If you need something more portable to non-Microsoft compilers, you will likely have to resort to writing a custom std::basic_streambuf class (or maybe derived from std::filebuf) to wrap your HANDLE, and then pass an object of that class to the std::basic_istream constructor directly.

Why I am unable to open a file RW with CreateFile Win32 API but can remove it with std::remove?

Windows has specific DELETE permissions (not relevant for FAT filesystems, but natively implemented on NTFS). These are independent from WRITE permissions. Permissions might exist on the file itself or be inherited from the parent (i.e. directory).

On Unix and Linux, things are slightly different; files deletes are handled there via write permissions on the parent directory.

Is there a way to write into a file while another process is reading?

You're on Windows, so the C++ way is

CreateFile(.... FILE_SHARE_READ | FILE_SHARE_WRITE, ....)

It returns a Win32 HANDLE, which is not the easiest thing to use in C++ (there are no convenience functions for formatted I/O). But you can turn it into a FILE* or fstream.

See this question:

  • Can I use CreateFile, but force the handle into a std::ofstream?

Or, you can use the shflag parameter of _fsopen() or the _Prot parameter of an fstream constructor:

The argument shflag is a constant expression consisting of one of the
following manifest constants, defined in Share.h.

Term      Definition

_SH_COMPAT Sets Compatibility mode for 16-bit applications.

_SH_DENYNO Permits read and write access.

_SH_DENYRD Denies read access to the file.

_SH_DENYRW Denies read and write access to the file.

_SH_DENYWR Denies write access to the file.

MSDN has the documentation and examples



Related Topics



Leave a reply



Submit