How to construct a c++ fstream from a POSIX file descriptor?
From the answer given by Éric Malenfant:
AFAIK, there is no way to do this in
standard C++. Depending on your
platform, your implementation of the
standard library may offer (as a
nonstandard extension) a fstream
constructor taking a file descriptor
as input. (This is the case for
libstdc++, IIRC) or a FILE*.
Based on above observations and my research below there's working code in two variants; one for libstdc++ and another one for Microsoft Visual C++.
libstdc++
There's non-standard __gnu_cxx::stdio_filebuf
class template which inherits std::basic_streambuf
and has the following constructor
stdio_filebuf (int __fd, std::ios_base::openmode __mode, size_t __size=static_cast< size_t >(BUFSIZ))
with description This constructor associates a file stream buffer with an open POSIX file descriptor.
We create it passing POSIX handle (line 1) and then we pass it to istream's constructor as basic_streambuf (line 2):
#include <ext/stdio_filebuf.h>
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
ofstream ofs("test.txt");
ofs << "Writing to a basic_ofstream object..." << endl;
ofs.close();
int posix_handle = fileno(::fopen("test.txt", "r"));
__gnu_cxx::stdio_filebuf<char> filebuf(posix_handle, std::ios::in); // 1
istream is(&filebuf); // 2
string line;
getline(is, line);
cout << "line: " << line << std::endl;
return 0;
}
Microsoft Visual C++
There used to be non-standard version of ifstream's constructor taking POSIX file descriptor but it's missing both from current docs and from code. There is another non-standard version of ifstream's constructor taking FILE*
explicit basic_ifstream(_Filet *_File)
: _Mybase(&_Filebuffer),
_Filebuffer(_File)
{ // construct with specified C stream
}
and it's not documented (I couldn't even find any old documentation where it would be present). We call it (line 1) with the parameter being the result of calling _fdopen to get C stream FILE* from POSIX file handle.
#include <cstdio>
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
ofstream ofs("test.txt");
ofs << "Writing to a basic_ofstream object..." << endl;
ofs.close();
int posix_handle = ::_fileno(::fopen("test.txt", "r"));
ifstream ifs(::_fdopen(posix_handle, "r")); // 1
string line;
getline(ifs, line);
ifs.close();
cout << "line: " << line << endl;
return 0;
}
Creating fstream object from a FILE* pointer
You cannot do that just in standard C++, since iostreams and C I/O are entirely separate and unrelated. You could however write your own iostream that's backed by a C FILE stream. I believe that GCC comes with one such stream class as a library extension.
Alternatively, if all you want is an object-y way of wrapping a C FILE stream, you could use a unique pointer for that purpose.
Getting a FILE* from a std::fstream
The short answer is no.
The reason, is because the std::fstream
is not required to use a FILE*
as part of its implementation. So even if you manage to extract file descriptor from the std::fstream
object and manually build a FILE object, then you will have other problems because you will now have two buffered objects writing to the same file descriptor.
The real question is why do you want to convert the std::fstream
object into a FILE*
?
Though I don't recommend it, you could try looking up funopen()
.
Unfortunately, this is not a POSIX API (it's a BSD extension) so its portability is in question. Which is also probably why I can't find anybody that has wrapped a std::stream
with an object like this.
FILE *funopen(
const void *cookie,
int (*readfn )(void *, char *, int),
int (*writefn)(void *, const char *, int),
fpos_t (*seekfn) (void *, fpos_t, int),
int (*closefn)(void *)
);
This allows you to build a FILE
object and specify some functions that will be used to do the actual work. If you write appropriate functions you can get them to read from the std::fstream
object that actually has the file open.
How to get a FILE* stream from a file descriptor?
FILE *fdopen(int fd, const char *mode);
See fdopen(3)
, but it should be on the same page as fopen(3)
:
The
fdopen()
function associates a stream with the existing
file descriptor, fd. The mode of the stream (one of the values
"r"
,"r+"
,"w"
,"w+"
,"a"
,"a+"
) must be compatible
with the mode of the file descriptor. The file position indicator
of the new stream is set to that belonging to fd, and the error and
end-of-file indicators are cleared. Modes"w"
or"w+"
do not
cause truncation of the file. The file descriptor is notdup
’ed,
and will be closed when the stream created byfdopen()
is
closed. The result of applyingfdopen()
to a shared memory object
is undefined.
How can I convert a file pointer ( FILE* fp ) to a file descriptor (int fd)?
The proper function is int fileno(FILE *stream)
. It can be found in <stdio.h>
, and is a POSIX standard but not standard C.
Can I use a FILE* to initialize a C++ ostream object?
With GCC you can just pass the existing file descriptor to the constructor (ref):
FILE *f = ...;
std::ofstream os(fileno(f));
Constructor: ofstream::ofstream (int fd)
Make an ofstream for writing to a file that was already open, using file descriptor fd.
How to open custom I/O streams from within a C++ program?
It is not possible if you need your program to be portable. The C++ 11 Standard does not specify a unified way of doing that.
However, you can define your own output stream buffer which overrides the overflow()
and xsputn()
virtual functions and writes each character or sequence of characters to the stream with the specified descriptor using system-specific API.
Something along these lines:
class my_ostream_buf : public std::streambuf
{
public:
my_ostream_buf(int fd) : _fd(fd) { }
protected:
virtual int_type overflow (int_type c)
{
if (c != EOF)
{
char ch = c;
if (write(_fd, &ch, 1) != 1)
{
return EOF;
}
}
return c;
}
// This is not strictly necessary, but performance is better if you
// write a sequence of characters all at once rather than writing
// each individual character through a separate system call.
virtual std::streamsize xsputn(const char* s, std::streamsize num)
{
return write(_fd, s, num);
}
private:
int _fd = 0;
};
And this is how you would use it:
using namespace std;
int main()
{
int fd = ...; // Any file descriptor
my_ostream_buf buf(fd);
ostream os(&buf); // Take care of the lifetime of `buf` here, or create your
// own class that derives from ostream and encapsulates an
// object of type my_ostream_buf
os << "Hello" << endl;
}
Get FILE stream from File Handle
Use _open_osfhandle()
to create a C-style file descriptor from a Win32 HANDLE
, and then use _fdopen()
to create a FILE*
from the file descriptor.
Related Topics
Recommended Way to Initialize Srand
Why How to Use Auto on a Private Type
Why Is the Type of the Main Function in C and C++ Left to the User to Define
Sfinae Working in Return Type But Not as Template Parameter
Two Phase Lookup - Explanation Needed
How to Write a Large Buffer into a Binary File in C++, Fast
Will Std::String Always Be Null-Terminated in C++11
What Happens If I Assign a Negative Value to an Unsigned Variable
Why Is There an Injected Class Name
Pure Virtual Function With Implementation
Concurrency: Atomic and Volatile in C++11 Memory Model
Why Does Cout Print Char Arrays Differently from Other Arrays
Gcc Optimization Flag -O3 Makes Code Slower Than -O2
When Does a Constexpr Function Get Evaluated At Compile Time