Getting a HANDLE from a std::ofstream - c++

Is it possible to get the underlying file HANDLE from a std::ofstream (Visual C++ 2005)?
This is the opposite of this question:
Can I use CreateFile, but force the handle into a std::ofstream?
The reason I want to so this is to modify attributes of the file (e.g. creation time) without having to open the file with CreateFile.

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.

My answer should be prefaced with "I am a Unix developer, not a Windows developer." But I had the same problem that you did, and this is how I chose to address it. I would love to have a better answer. My answer below will make your skin crawl, but it worked.
First off, we'll need the _Filet* from the fdbuf. This is a private member, so we can't just create a new class that gives us visibility into it. So, I modify the header for fstream to add a new friend function in filebuf, so that the specific function will let us cheat and get access to that member (I added it just below the definition "_Filet *_Myfile;"):
friend HANDLE __HACK_getFilebufHANDLE(filebuf*);
Now we have a public function to access the private member. Step two is to write the function:
namespace std {
HANDLE __HACK_getFilebufHANDLE(filebuf*in) {
return (HANDLE) _get_osfhandle(_fileno(in->_Myfile));
}
};
Lastly, you just need to call it, except that rdbuf returns the wrong type (iobuf rather than filebuf). Since we're already off in "here there be dragons" for this entire process, we may as well make everyone's skin crawl (but in real life, do type checking here to validate the cast to the derived type):
__HACK_getFilebufHANDLE((filebuf*)fopoutstrm.rdbuf())
Sorry that I don't have a cleaner answer.

No. You can't even get at the FILE* (or _Filet* as it's internally known) inside std::basic_filebuf.

This is not possible in standard C++. However, with Boost.IOStreams library it is not that hard. Create a Device, wrap it in a boost::iostreams::stream_buffer<> and add appropriate stream using boost::iostreams::stream<>.

With the VisualC++ 2010 libraries, the following should work. I assume it's the same for VisualC++ 2005, but you will have to verify:
FILE* fh = fopen(...);
HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(fh));
// do something on hFile
// create iostream from FILE
std::ifstream ifs(fh);
// use it...
// close FILE
_close(fh);

No. I try many ways.
this line: "std::ifstream ifs(fh);" may not wrok in some msvs, such as 2008.
I find another way, you can enumerate handle in your process, and find the handle that releated to the filename.
In this way, I get the handle.

Related

Retrieve information about an open file

Can I retrieve information about a file previously opened with fopen() using only the pointer it returned?
The reason I ask is that I am trying to write a RAII-style wrapper class for FILE *s, and I want to make it as general as possible, and one of the functions I imagined for it was a copy-like operation, that would take a FILE * as an argument, and create a new reference to the same file.
Under POSIX, I can create a duplicate of a file descriptor with dup()/dup2(), and even get how the file is being accessed with fnctl()'s F_GETFL operation. However, even if I do that to the underlying descriptor of a FILE *, it isn't enough for guessing properties such as if the stream is text or binary (under POSIX, there no real difference, but I want to be general), or its orientation towards char- or wchar_t-based text.
So, is there is a way of learning about the stream I'm about to create a wrapper for, how far can I go, and how should I do it?
Thank you for you attention.

fstream delete N bytes from the end of a binary file

Is it possible to delete N bytes from the end of a binary file in C++ using fstream (or something similar)? I don´t want to read the whole file, cut it and write it again, but since it´s from the end of a file it seems like it shouldn't be such a problem.
I'm not aware of a generic C++ (platform independent) way to do this without writing a new file. However, on POSIX systems (Linux, etc.) you can use the ftruncate() function. On Windows, you can use SetEndOfFile().
This also means you'll need to open the file using the native functions instead of fstream since you need the native descriptor/handle for those functions.
EDIT: If you are able to use the Boost library, it has a resize_file() function in its Filesystem library which would do what you want.
Update:
Now in C++17 you can use resize_file from filesystem
Live on Coliru
In case you want to use Qt, QFile also provides two resize() methods that allow to truncate a file.

Redirect FILE handle to char-buffer

I'm using a third-party library that allows conversion between two file formats A and B. I would like to use this library to load a file of format A and convert it to format B, but I only need the converted representation in memory. So I would like to do the conversion without actually saving a file of the target format to disk and rather obtain an unsigned char* buffer or something similar. Unfortunately the libraries only conversion function is of the form
void saveAsB(A& a, std::FILE *const file);
What can I do? Is there any way to redirect the write operations performed on the handle to some buffer?
If your platform supports it, use open_memstream(3). This will be available on Linux and BSD systems, and it's probably better than fmemopen() for your use case because open_memstream() allocates the output buffer dynamically rather than you having to know the maximum size in advance.
If your platform doesn't have those functions, you can always use a "RAM disk" approach, which again on Linux would be writing a "file" to /dev/shm/ which will never actually reach any disk, but rather be stored in memory.
Edit: OK, so you say you're using Windows. Here's an outline of what you can try:
Open a non-persisted memory-mapped files.
Use _open_osfhandle to convert the HANDLE to an int file descriptor.
Use _fdopen to convert the int file descriptor to FILE*.
Cross your fingers. I haven't tested any of this.
I found this reference useful in putting the pieces together: http://www.codeproject.com/Articles/1044/A-Handy-Guide-To-Handling-Handles
Edit 2: It looks like CreateFileMapping() and _open_osfhandle() may be incompatible with each other--you would be at least the third person to try it:
https://groups.google.com/forum/#!topic/comp.os.ms-windows.programmer.win32/NTGL3h7L1LY
http://www.progtown.com/topic178214-createfilemapping-and-file.html
So, you can try what the last link suggested, which is to use setvbuf() to "trick" the data into flowing to a buffer you control, but even that has potential problems, e.g. it won't work if the library seeks within the FILE*.
So, perhaps you can just write to a file on some temporary/scratch filesystem and be done with it? Or use a platform other than Windows? Or use some "RAM disk" software.
If you can rely on POSIX being available, then use fmemopen().

What does ifstream::open() really do?

Consider this code:
ifstream filein;
filein.open("y.txt");
When I use the open() function, what happens?
Does the file stream itself get opened?
or does the object's state change to open?
or both?
It's not clear if you want to know implementation details or standard requirements - but as for implementation details - it will call the underlying open system call on the operating system. On Linux for example this is called open. On Windows it is called CreateFile.
The filestream being open or closed is represented by it's state. So if you change the state to open, the filestream is now open. Like a doorway. If you open it, you've changed it's state to the open position. Then you can later close it, which involves changing it's state to the closed position. Changing its state to open and opening the stream are the exact same thing.
The std::ifstream is set up to own a std::filebuf which is a class derived from std::streambuf. The stream buffer is managing buffering for streams in a generic way and abstracts the details of how a stream is accessed. For a std::filebuf the underlying stream is an operating system file accessed as needed. When std::ifstream::open() is called this call is mainly delegated to std::filebuf::open() which does the actual work. However, the std::ifstream will clear() its state bits if the call to std::filebuf::open() succeeds and set std::ios_base::failbit if the call fails. The file buffer will call the system's method to allocate a file handle and, if successful, arrange for this file handle to be released in its destructor or in the std::filebuf::close() function - whatever comes first. When calling std::ifstream::open() with the default arguments the system call will check that the file exists, is accessible, not too many file handles are open, etc. There is an std::ios_base::openmode parameter which can be used to modify the behavior in some ways and when different flags are used when calling std::ofstream::open().
Whether the call to std::filebuf::open() has any other effects is up to the implementation. For example, the implementation could choose to obtain a sequence of bytes and convert them into characters. Since the user can override certain setting, in particular the std::locale (see the std::streambuf::pubimbue() function), it is unlikely that much will happen prior to the first read, though. In any case, none of the state flags would be affected by the outcome of any operation after opening the file itself.
BTW, the mentioned classes are actually all templates (std::basic_ifstream, std::basic_filebuf, std::basic_streambuf, and std::basic_ofstream) which are typedef'ed to the names used above for the instantiation working on char as a character type. There are similar typedefs using a w prefix for instantiations working on wchar_t. Interestingly, there are no typedefs for the char16_t and char32_t versions and it seems it will be a bit of work to get them instantiated as well.
If you think logically, ifstream is just the stream in which we will get our file contents. The parameters, we provide to ifstream.open() will open the file and mark it as open. When the file is marked as open, it will not allow you to do some operations on file like renaming a file as it is opened by some program. It will allow you to do the same after you close the stream. ifstream - imo is only the helper class to access files.

How can I create a temporary file for writing in C++ on a Linux platform?

In C++, on Linux, how can I write a function to return a temporary filename that I can then open for writing?
The filename should be as unique as possible, so that another process using the same function won't get the same name.
Use one of the standard library "mktemp" functions: mktemp/mkstemp/mkstemps/mkdtemp.
Edit: plain mktemp can be insecure - mkstemp is preferred.
tmpnam(), or anything that gives you a name is going to be vulnerable to race conditions. Use something designed for this purpose that returns a handle, such as tmpfile():
#include <stdio.h>
FILE *tmpfile(void);
The GNU libc manual discusses the various options available and their caveats:
http://www.gnu.org/s/libc/manual/html_node/Temporary-Files.html
Long story short, only mkstemp() or tmpfile() should be used, as others have mentioned.
man tmpfile
The tmpfile() function opens a unique temporary file in binary
read/write (w+b) mode. The file will be automatically deleted when it
is closed or the program terminates.ote
mktemp should work or else get one of the plenty of available libraries to generate a UUID.
The tmpnam() function in the C standard library is designed to solve just this problem. There's also tmpfile(), which returns an open file handle (and automatically deletes it when you close it).
You should simply check if the file you're trying to write to already exists.
This is a locking problem.
Files also have owners so if you're doing it right the wrong process will not be able to write to it.