2010-07-23 8 views
19

Me gustaría leer algunos datos de un flujo que tengo usando std::getline. Debajo de una muestra usando el std::cin.comprobando la disponibilidad de datos antes de llamar a std :: getline

std::string line; 
std::getline(std::cin, line); 

Esta es una función de bloqueo es decir, si no hay datos o línea para leerlo ejecución bloques.

¿Sabe si existe una función para verificar la disponibilidad de datos antes de llamar al std::getline? No quiero bloquear.

¿Cómo puedo verificar si el buffer de flujo está lleno de datos válidos para una llamada exitosa al std::getline?

Lo que se ve como el código de abajo

if(dataAvailableInStream()) 
{ 
    std::string line; 
    std::getline(std::cin, line); 
} 
+1

Usted dice que no desea bloquear, pero su ejemplo usa std :: cin. Cuéntanos qué intentas lograr y quizás podamos aclarar nuestras respuestas para ser más útiles. – nathan

+0

¡Hola a todos! Tengo un istream de bloqueo. En lo específico, estoy usando la biblioteca POCO para procesos y quiero leer de POCO :: PipeInputStream. Mi pregunta era: 1. Sé que llamar a std :: getline con una secuencia de bloqueo se bloquearía si no hay datos disponibles 2. ¿Qué función llamar para verificar si los datos están disponibles? 3. si NO hay datos disponibles, estoy no va a llamar a std :: getline porque bloquea –

+0

(Esto todavía aparece en los resultados de búsqueda.) Vea mi respuesta aquí: http://stackoverflow.com/a/42264216/1599699 – Andrew

Respuesta

8

La biblioteca iostream no es compatible con el concepto de E/S sin bloqueo. No creo que haya nada en el estándar de C++ que sí lo haga. Cualquier buena solución probablemente sea específica de la plataforma. Si puede usar las bibliotecas POSIX, puede consultar select. Por lo general, se usa para crear redes, pero funcionará bien si le pasa el descriptor de archivo para stdin.

-2

std :: iostream proporciona una función peek que devuelve el siguiente carácter en la corriente sin eliminarlo. Entonces podrías hacer algo como lo siguiente (totalmente no probado).

bool dataAvailableInStream(std::iostream &stream) 
{ 
    return stream.peek() != std::iostream::traits_type::eof(); 
} 

Editar

Como rubenvb señala, std::cin bloques por diseño. Por lo tanto, el código anterior lo hará pasar bloqueando getline, pero no cin.

Editar Editar

Como Charles señala a continuación, peek bloques si no hay datos disponibles. Por lo tanto, esto no proporciona una solución completa. Le impedirá bloquear en getline, pero no bloqueará en general.

+1

O 'return stream.peek()! = std :: eof; 'si no te gusta la verborrea. –

+0

@Mike lol. Lo editaré para reflejar su implementación. – nathan

+4

¡NO FUNCIONA! Probé y miré() bloques como std :: getline() cuando no hay nada que leer. –

0

Aunque peek() respuesta de Nathan será ver si hay datos, no hay ninguna garantía de que std::getline() tendrán éxito en la lectura de una "línea".

Siempre es mucho más fácil aunque un poco hacia atrás para tratar getline y comprobar el resultado de ti función de llamarse a sí misma:

std::string line; 
while(!std::getline(std::cin, line)) 
{ 
    cout << "Enter something please" << endl; 
} 

Este código se ejecutará hasta cin recibe algo que le gusta (es decir, se puede extraer y colocar en line). No veo que peek() sea necesario o útil aquí.

EDITAR: El asunto es que cin (== entrada de teclado estándar) tendrá que bloquear el programa mientras espera la entrada, ¿de qué otra forma puede obtener una entrada cuando no espera?

+0

Buen punto sobre cin, no había considerado que bloquearía. – nathan

15

No hay una forma estándar de verificar si getline se bloqueará. Se puede utilizar:

std::cin.rdbuf()->in_avail() 

para ver cuántos caracteres son definitivamente disponible antes de una operación de lectura puede bloquear, pero que tendría que leer los caracteres uno por uno antes de volver a comprobar in_avail ya que no hay manera de saber de avanzar si alguno de los caracteres pendientes es una línea nueva o el final real de la secuencia. Una llamada getline podría bloquear si este no fuera el caso.

Tenga en cuenta que aunque in_avail() devuelve un número positivo, se garantiza que al menos hay tantos caracteres disponibles antes del final de la transmisión, lo contrario no es cierto. Si in_avail() devuelve cero, es posible que aún haya caracteres disponibles y que la transmisión no se bloquee inmediatamente.

+2

Esto no funciona muy bien con MSVC 2013. Parece devolver un valor positivo incluso cuando la transmisión no está cerrada y no hay entradas disponibles. No perderé un día probándolo, pero definitivamente creo que está podrido. –

+4

"Definitivamente creo que está podrido". - ¿Qué, MSVC? ;-) – DevSolar

0

¿Qué problema estás tratando de resolver evitando el bloqueo de lectura aquí?

No portátil Puedo imaginar que podría usar poll o select para ver si hay datos para leer en stdin (a menudo fd 0 en sistemas Unix).

Alternativamente, podría crear un segundo hilo para hacer E/S y simplemente dejarlo bloquear para que pueda continuar el procesamiento normal en el hilo principal.

+1

si utilizo un segundo hilo, por lo que sé, hay un problema para matar el hilo, por lo que es mejor vivirlo hasta el final de la aplicación. ¿Tiene esto sentido? –

1

Un truco podría ser llamar a kbhit() antes de la lectura. Probablemente no es portátil y lleno de peligros ...

#include <conio.h> 
#include <iostream> 

using namespace std; 


char buffer[128]; 

if (kbhit()) 
{ 
    cin.getline(buffer, sizeof(buffer)); 
} 
2

Este código puede ayudar a comprobar la existencia de datos en el stdin sin bloquear:

std::cin.seekg(0, std::cin.end); 
int length = std::cin.tellg(); 
if (length < 0) return; //- no chars available 

Si stdin tiene algunos datos - no se olvide para establecer la posición de nuevo al comienzo.

std::cin.seekg(0, std::cin.beg); 

continuación, puede leer todos los datos incluyendo \0 (puede haber más de una) al final de la memoria intermedia:

std::vector<char> s(length); 
std::cin.read(s.data(), length); 

o línea por línea:

std::string line; 
while (std::cin) { 
    std::getline(std::cin, line); 
    //..... 
} 

Este código funciona en MSVC y gcc (Ubuntu)

Cuestiones relacionadas