2011-10-18 12 views
11

Estoy escribiendo una aplicación C++ y necesito leer el resultado de un comando del sistema.Lectura de resultados popen en C++

estoy usando popen() más o menos como se muestra aquí:

const int MAX_BUFFER = 2048; 
    string cmd="ls -l"; 
    char buffer[MAX_BUFFER]; 
    FILE *stream = popen(cmd.c_str(), "r"); 
    if (stream){ 
     while (!feof(stream)) 
     { 
      if (fgets(buffer, MAX_BUFFER, stream) != NULL) 
      { 
       //here is all my code 
      } 
     } 
     pclose(stream); 
    } 

que he estado tratando de volver a escribir esto de una manera diferente. Vi algunas soluciones no estándar como:

FILE *myfile; 
std::fstream fileStream(myfile); 
std::string mystring; 
while(std::getline(myfile,mystring)) 
{ 
    // .... Here I do what I need 
} 

Mi compilador no acepta esto sin embargo.

¿Cómo puedo leer desde popen en C++?

+0

¿Qué es 'here all my code'? Su primera solución funciona perfectamente si es 'data.append (buffer);'. – Beta

+1

¿Podría publicar la pila de llamadas de su caída? – Arkadiy

+0

Proporcione un programa ** completo ** mínimo que demuestre su error. Comience con su programa actual, elimine todas las líneas que funcionan y muéstrenos lo que queda. [Aquí] (http://ideone.com/azOcT) es un ejemplo de una implementación en funcionamiento de su primer fragmento de código. Consulte http://sscce.org para obtener más información sobre el uso de esta técnica. –

Respuesta

15

Su ejemplo:

FILE *myfile; 
std::fstream fileStream(myfile); 
std::string mystring; 
while(std::getline(myfile,mystring)) 

trabajo does't porque a pesar de que está muy cerca de la biblioteca estándar no proporciona una fstream que puede ser construido a partir de una FILE*. Boost iostreams proporciona un iostream que se puede construir a partir de un descriptor de archivo y puede obtener uno de FILE* llamando al fileno.

ej .:

typedef boost::iostreams::stream<boost::iostreams::file_descriptor_sink> 
     boost_stream; 

FILE *myfile; 
// make sure to popen and it succeeds 
boost_stream stream(fileno(myfile)); 
stream.set_auto_close(false); // https://svn.boost.org/trac/boost/ticket/3517 
std::string mystring; 
while(std::getline(stream,mystring)) 

No se olvide de pclose más tarde aún.

Nota: Las versiones más recientes de boost han dejado en desuso el constructor que solo toma un fd. En su lugar, debe pasar uno de boost::iostreams::never_close_handle o boost::iostreams::close_handle como segundo argumento obligatorio para el constructor.

+0

Algunos compiladores proporcionan extensiones no estándar para la biblioteca estándar de C++. Un constructor de fstream que toma un ARCHIVO * es muy popular. Lo que explica por qué funciona en algunos compiladores y no en otros. – Sjoerd

+0

@Sjoerd - ah sí, eso tendría sentido. Me preguntaba por qué se escribiría así. Aún así, puede usar un typedef para elegir entre una extensión no estándar y una biblioteca de impulso en el momento de la configuración en su herramienta de compilación. – Flexo

+1

intenté con el constructor estándar para fstream pero no fue aceptado en mi caso. Lo intentaré ahora de esta manera ... – Stefano

-5

Aquí hay algo que escribí hace mucho tiempo, puede ser de ayuda. Puede tener algunos errores.

#include <vector> 
#include <string> 
#include <stdio.h> 
#include <iostream> 

bool my_popen (const std::string& cmd,std::vector<std::string>& out) { 
    bool   ret_boolValue = true; 
    FILE*   fp; 
    const int  SIZEBUF = 1234; 
    char   buf [SIZEBUF]; 
    out = std::vector<std::string>(); 
    if ((fp = popen(cmd.c_str(), "r")) == NULL) { 
     return false; 
    } 
    std::string cur_string = ""; 
    while (fgets(buf, sizeof (buf), fp)) { 
     cur_string += buf; 
    } 
    out.push_back (cur_string.substr (0, cur_string.size() - 1)); 
    pclose(fp); 
    return true; 
} 
int main (int argc, char **argv) { 
     std::vector<std::string> output; 
     my_popen("ls -l > /dev/null ", output); 
     for (std::vector<std::string>::iterator itr = output.begin(); 
               itr != output.end(); 
               ++itr) { 
       std::cout << *itr << std::endl; 
     } 

}