2009-11-05 55 views
8

Załóżmy, że "popen" plik wykonywalny, otrzymuję w zamian FILE*. Co więcej, przypuśćmy, że chciałbym "połączyć" ten plik z obiektem istream w celu łatwiejszego przetwarzania, czy jest na to jakiś sposób?PLIK * i istream: połączyć dwa?

Odpowiedz

4

Nie ma standardowej metody, ale jeśli chcesz uzyskać szybkie rozwiązanie, możesz uzyskać deskryptor pliku za pomocą fileno(), a następnie użyć Josuttis 'fdstream. Mogą być podobne wysiłki, ale użyłem tego w odległej przeszłości i wszystko działało dobrze. Jeśli nic innego, to powinna być bardzo dobra mapa do realizacji własnych.

1

Na pewno jest sposób, zaimplementuj własny istream, który można skonstruować z FILE*.

Jeśli pytasz, czy istnieje standardowy sposób, aby to zrobić, to nie.

13

Możesz uciec, wyprowadzając klasy std :: basic_streambuf lub std :: streambuf.
Coś w tym stylu:

#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

+1 Bardzo przydatne! Dobra robota :-) – jweyrich