FILE * and istream: connect the two?

后端 未结 3 1980
误落风尘
误落风尘 2020-12-10 15:37

Suppose I \"popen\" an executable, I get a FILE* in return. Furthermore, suppose I\'d like to \"connect\" this file to an istream object for easier

相关标签:
3条回答
  • 2020-12-10 16:22

    There is no standard way but if you want a quick solution you can get the file descriptor with fileno() and then use Josuttis' fdstream. There may be similar efforts around but I used this in the distant past and it worked fine. If nothing else it should be a very good map to implementing your own.

    0 讨论(0)
  • 2020-12-10 16:39

    Sure there's a way, implement your own istream that can be constructed from a FILE*.

    If you're asking whether there is a standard way to do this, then no.

    0 讨论(0)
  • 2020-12-10 16:40

    You can get away by deriving std::basic_streambuf or std::streambuf classes.
    Something along these lines:

    #include <stdio.h>
    #include <iostream>
    
    #define BUFFER_SIZE     1024
    
    class popen_streambuf : public std::streambuf {
    public:
        popen_streambuf() : fp(NULL) {
        }
        ~popen_streambuf() {
            close();
        }
        popen_streambuf *open(const char *command, const char *mode) {
            fp = popen(command, mode);
            if (fp == NULL)
                return NULL;
            buffer = new char_type[BUFFER_SIZE];
            // It's good to check because exceptions can be disabled
            if (buffer == NULL) {
                close();
                return NULL;
            }
            setg(buffer, buffer, buffer);
            return this;
        }
        void close() {
            if (fp != NULL) {
                pclose(fp);
                fp = NULL;
            }
        }
        std::streamsize xsgetn(char_type *ptr, std::streamsize n) {
            std::streamsize got = showmanyc();
            if (n <= got) {
                memcpy(ptr, gptr(), n * sizeof(char_type));
                gbump(n);
                return n;
            }
            memcpy(ptr, gptr(), got * sizeof(char_type));
            gbump(got);
    
            if (traits_type::eof() == underflow()) {
                return got;
            }
            return (got + xsgetn(ptr + got, n - got));
        }
        int_type underflow() {
            if (gptr() == 0) {
                return traits_type::eof();
            }
            if (gptr() < egptr()) {
                return traits_type::to_int_type(*gptr());
            }
            size_t len = fread(eback(), sizeof(char_type), BUFFER_SIZE, fp);
            setg(eback(), eback(), eback() + (sizeof(char_type) * len));
            if (0 == len) {
                return traits_type::eof();
            }
            return traits_type::to_int_type(*gptr());
        }
        std::streamsize showmanyc() {
            if (gptr() == 0) {
               return 0;
            }
            if (gptr() < egptr()) {
                return egptr() - gptr();
            }
            return 0; 
        }
    private:
        FILE *fp;
        char_type *buffer;
    };
    
    int main(int argc, char *argv)
    {
        char c;
        popen_streambuf sb;
        std::istream is(&sb);
    
        if (NULL == sb.open("ls -la", "r")) {
            return 1;
        }
    
        while (is.read(&c, 1)) {
            std::cout << c;
        }
    
        return 0;
    }
    
    0 讨论(0)
提交回复
热议问题