6

For a project I MUST read/write using a C-style file type. It could be regular FILE, or a C version of gzfile, etc. I'd still like the convenience of using C++ streams. Is there a stream class that redirects to C-style file operations internally? So myfile << hex << myint eventually becomes fprintf("%a", myint) or something similar?

Neil Kirk
  • 21,327
  • 9
  • 53
  • 91

2 Answers2

3

There isn't a standard one, but if you MUST do this then you'll have to use something non-standard.

GCC's standard library includes a streambuf type, __gnu_cxx::stdio_filebuf, which can be constructed with a FILE* (or a file descriptor), which you can use to replace the streambuf of an fstream, or just use with a plain iostream e.g.

#include <stdio.h>
#include <ext/stdio_filebuf.h>
#include <fstream>

int main()
{
    FILE* f = fopen("test.out", "a+");
    if (!f)
    {
        perror("fopen");
        return 1;
    }
    __gnu_cxx::stdio_filebuf<char> fbuf(f, std::ios::in|std::ios::out|std::ios::app);
    std::iostream fs(&fbuf);
    fs << "Test\n";
    fs << std::flush;
    fclose(f);
}

Things to note about this:

  • the stdio_filebuf must not go out of scope while the iostream is still referring to it
  • you need to manually close the FILE*, the stdio_filebuf won't do that when constructed from a FILE*
  • be sure to flush the stream before closing the FILE*, otherwise there could be unwritten data sitting in the stdio_filebuf's buffer that cannot be written out after the FILE* is closed.
Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
  • 3
    In your current code sample, fclose() will be called before the stream and buffer's destructors. Even if flushed first, this may be an undefined behavior: You should add a `{}` block that ends before the call to fclose(). – Medinoc Oct 09 '13 at 12:37
  • @Medinoc This is a library extension. Check the source code. I'd hazard a guess Jonathan, being a libstdc++ author, knows how to use its extensions `;-)`. – rubenvb Oct 09 '13 at 12:53
  • 1
    Well it's a long time since I've used those classes so I might have got it wrong. Medinoc's advice is a good idea, although I'm pretty sure it's not going to result in undefined behaviour, you just might lose data and `errno` will get set – Jonathan Wakely Oct 09 '13 at 13:24
2

What you need is an implementation of the streambuf class that writes on a C file. If there isn't already one in the C++ standard (which would disappoint me a bit, but not surprise me), you can make one and override the right methods.

Note that it will never translate << as fprintf(file, ...): the result will be more akin to sprintf(buf, ...); fwrite(file, buf).

Medinoc
  • 6,577
  • 20
  • 42