Retrieving File Descriptor from a Std::Fstream

Retrieving file descriptor from a std::fstream

You can go the other way: implement your own stream buffer that wraps a file descriptor and then use it with iostream instead of fstream. Using Boost.Iostreams can make the task easier.

Non-portable gcc solution is:

#include <ext/stdio_filebuf.h>

{
int fd = ...;
__gnu_cxx::stdio_filebuf<char> fd_file_buf{fd, std::ios_base::out | std::ios_base::binary};
std::ostream fd_stream{&fd_file_buf};
// Write into fd_stream.
// ...
// Flushes the stream and closes fd at scope exit.
}

How to open an ifstream from a file descriptor?

Short answer: you can't, not in standard C++ anyway. There is no official/portable way to do it.

You can, however, find some "work-around" solutions in these previous posts:

How to construct a c++ fstream from a POSIX file descriptor?

Getting a FILE* from a std::fstream

Retrieving file descriptor from a std::fstream

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 file id from std::ofstream

There is no standard way to get a file descriptor from a standard fstream. There may be a platform specific method, depending on your standard library implementation.

If you're using libstdc++ then according to this there may be a filedesc() method on the fstream object that gives you what you want.

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.

Handle socket descriptors like file descriptor (fstream)? C++/Linux

The standard file stream doesn't support use of a file descriptor. However, the I/O stream classes make it reasonably easy to create your own abstraction which allows creating your own sources of or destination for characters. The magic class is std::streambuf whose responsibility is to buffer characters and read or write characters at appropriate times. Nicolai Josuttis's "The C++ Standard Library" has a detailed description of how to do so (the basis of which I contributed to Nico many years ago). A simple implementation of a stream buffer using a socket for reading and writing would look something like this:

#include <algorithm>
#include <iostream>
#include <iterator>
#include <streambuf>
#include <cstddef>
#include <unistd.h>

class fdbuf
: public std::streambuf
{
private:
enum { bufsize = 1024 };
char outbuf_[bufsize];
char inbuf_[bufsize + 16 - sizeof(int)];
int fd_;
public:
typedef std::streambuf::traits_type traits_type;

fdbuf(int fd);
~fdbuf();
void open(int fd);
void close();

protected:
int overflow(int c);
int underflow();
int sync();
};

fdbuf::fdbuf(int fd)
: fd_(-1) {
this->open(fd);
}

fdbuf::~fdbuf() {
this->close();
}

void fdbuf::open(int fd) {
this->close();
this->fd_ = fd;
this->setg(this->inbuf_, this->inbuf_, this->inbuf_);
this->setp(this->outbuf_, this->outbuf_ + bufsize - 1);
}

void fdbuf::close() {
if (!(this->fd_ < 0)) {
this->sync();
::close(this->fd_);
}
}

int fdbuf::overflow(int c) {
if (!traits_type::eq_int_type(c, traits_type::eof())) {
*this->pptr() = traits_type::to_char_type(c);
this->pbump(1);
}
return this->sync() == -1
? traits_type::eof()
: traits_type::not_eof(c);
}

int fdbuf::sync() {
if (this->pbase() != this->pptr()) {
std::streamsize size(this->pptr() - this->pbase());
std::streamsize done(::write(this->fd_, this->outbuf_, size));
// The code below assumes that it is success if the stream made
// some progress. Depending on the needs it may be more
// reasonable to consider it a success only if it managed to
// write the entire buffer and, e.g., loop a couple of times
// to try achieving this success.
if (0 < done) {
std::copy(this->pbase() + done, this->pptr(), this->pbase());
this->setp(this->pbase(), this->epptr());
this->pbump(size - done);
}
}
return this->pptr() != this->epptr()? 0: -1;
}

int fdbuf::underflow()
{
if (this->gptr() == this->egptr()) {
std::streamsize pback(std::min(this->gptr() - this->eback(),
std::ptrdiff_t(16 - sizeof(int))));
std::copy(this->egptr() - pback, this->egptr(), this->eback());
int done(::read(this->fd_, this->eback() + pback, bufsize));
this->setg(this->eback(),
this->eback() + pback,
this->eback() + pback + std::max(0, done));
}
return this->gptr() == this->egptr()
? traits_type::eof()
: traits_type::to_int_type(*this->gptr());
}

int main()
{
fdbuf inbuf(0);
std::istream in(&inbuf);
fdbuf outbuf(1);
std::ostream out(&outbuf);

std::copy(std::istreambuf_iterator<char>(in),
std::istreambuf_iterator<char>(),
std::ostreambuf_iterator<char>(out));
}

How to Access File Descriptor of Open File

If you're trying to get to the FILE* from the stream then the answer is basically "you can't" as stated by more enlightened people than me here.



Related Topics



Leave a reply



Submit