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.
Related
Assume I am writing a class to wrap windows' file HANDLE to give functionality to read/write from files easily. The class has a functions called read(buffer& out) that reads data from the file.
The question is, does read() need to be const or not?
On one hand, it should be const because it doesn't change the file.
On the other hand, it shouldn't be const because it changes the HANDLE (the HANDLE to the file which shows where to read).
What do you think?
Not const. Modifies the file handle position.
It sounds like your class - I'll call it FileAccessor - is effectively orchestrating operations on the file. Say you want to have a function implementing some algorithm processing the file, and it wants to display some diagnostic information by calling output_diagnostics(const FileAccessor& h), what information could it reasonable display that couldn't interfere with the algorithm calling output_diagnostics? It could perhaps output the current position / bytes-offset in the file. A function to get that position should be const. There might be other things, such as whether the file's locked in some way, the file size or filesystem path - all seem fair to make const. But, if it does a read from the file it's modifying what the algorithm calling output_diagnostic can expect should it later do a read, a "truncate from the current position" and all manner of other operations, and for that reason the read function should not be const.
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().
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.
Is it possible to clear the contents (ie. set EOF to the beginning/reset the file) in C++ knowing just the FILE*? I'm writing to a temp file with wb+ access and wish to sometimes clear it and truncate it without adding the calls to fclose and fopen. I dont think it's possible... but if not, why not?
Thanks in advance!
It will depend on your platform. The POSIX standard provides ftruncate(), which requires a file descriptor, not a FILE pointer, but it also provides fileno() to get the file descriptor from the FILE pointer.
The analogous facilities will be available in Windows environments - but under different names.
I don't believe this can be done using just the FILE*. You can always write null data through the end of the file but that won't truncate it.
Alternately if you have access to the filename (I can't tell from the question) you could use freopen which hides the close/open/truncate into a single function call.
#include <cstdio>
freopen(null, "w", filePtr);
see http://www.cplusplus.com/reference/clibrary/cstdio/freopen/ for more. espacialy the description for the parameter filename.
I wonder if we can get the file name including its path from the file object that we have created for the file name in C and in C++ respectively
FILE *fp = fopen(filename, mode); // in C
ofstream out(filename); // in C++
ifstream in(filename); // in C++
Thanks!
You can't, in general. The file may not ever have had a file name, as it may be standard input, output, or error, or a socket. The file may have also been deleted; on Unix at least, you can still read to or write from a file that has been deleted, as the process retains a reference to it so the underlying file itself is not deleted until the reference count goes to zero. There may also be more than one name for a file; you can have multiple hard links to a single file.
If you want to retain the information about where a file came from, I would suggest creating your own struct or class that consists of a filename and the file pointer or stream.
There is no portable way to retrieve the file name of a FILE* object. It may not even be associated with an actual file (e.g. a FILE pointer for stdout).
There is no portable way. However particular platforms sometimes have ways to do that.
In Windows, if you can get the file's HANDLE (like the one you get from ::CreateFile() ), you can get the path from that using something like ZwQueryInformationFile().
From a FILE *, you can get a (Unix-style) file id using _fileno(). Then call _get_oshandle() to get the HANDLE.
Not sure how to do that from an std::ofstream, but you can research that.
Not sure how to do that on other OSes but it may be possible.