2010-07-23 3 views
19

Я хотел бы прочитать некоторые данные из потока, который у меня есть std::getline. Ниже образца с использованием std::cin.проверка наличия данных перед вызовом std :: getline

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

Это блокирующая функция, т. Е. Если нет данных или строк для чтения, они блокируют выполнение.

Знаете ли вы, существует ли функция проверки доступности данных перед вызовом std::getline? Я не хочу блокировать.

Как проверить, заполнен ли буфер потока данными, действительными для успешного вызова, std::getline?

Независимо выглядит как код ниже

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

Вы говорите, что вы не хотите блокировать, но ваш пример использует std :: cin. Скажите нам, что вы пытаетесь выполнить, и, возможно, мы сможем уточнить наши ответы, чтобы быть более полезными. – nathan

+0

Привет всем! У меня есть блокирующий поток. В конкретном я использую библиотеку POCO для процессов, и я хочу читать из POCO :: PipeInputStream. Мой вопрос: 1. Я знаю, что вызов std :: getline с блокирующим потоком блокируется, если данные не доступны. 2. какую функцию вызывать, чтобы проверить, доступны ли данные. 3. если НЕТ данных нет не собирается вызывать std :: getline, потому что он блокирует –

+0

(это все еще отображается в результатах поиска.) См. мой ответ здесь: http://stackoverflow.com/a/42264216/1599699 – Andrew

ответ

8

Библиотека iostream не поддерживает концепцию неблокирующего ввода-вывода. Я не думаю, что в стандарте C++ есть что-то. Любое хорошее решение, вероятно, будет специфичным для платформы. Если вы можете использовать библиотеки POSIX, вы можете посмотреть на select. Обычно он используется для работы в сети, но он будет работать нормально, если вы передадите ему дескриптор файла для stdin.

-2

станд :: iostream предоставляет функцию быстрого взгляда, который возвращает следующий символ в потоке, не удаляя его. Таким образом, вы можете сделать что-то вроде следующего (полностью не тестировалось).

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

Редактировать

Как rubenvb указывает, std::cin блоки дизайна. Поэтому вышеприведенный код доставит вам getline блокировки, но не cin.

Править

Как Чарльз указывает ниже, peek блоки, если данные не доступны. Поэтому это не дает полного решения. Это не позволит вам блокировать getline, но не блокирует в целом.

+1

Или 'return stream.peek()! = std :: eof; 'если вы не в многословии. –

+0

@Mike lol. Я отредактирую его, чтобы отразить вашу реализацию. – nathan

+4

ЭТО НЕ РАБОТАЕТ! Я пробовал и заглядывал() как std :: getline(), когда читать нечего. –

0

Несмотря на то, что nathan's peek() ответ увидит, есть ли данные, нет гарантии, что std::getline() будет успешным в чтении «строки».

Это всегда намного проще, хотя и немного назад, чтобы попытаться GetLine и проверить результат тя вызова функции себя:

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

Этот код будет работать до тех пор, cin не получает что-то, что любит (т.е. может извлечь и поместить в line). Я не вижу здесь peek() здесь.

EDIT: Дело в том, что cin (== стандартный ввод на клавиатуре) должен будет блокировать программу, так как она ждет ввода, как еще она может получить какие-либо данные, когда она не будет ждать?

+0

Хороший вопрос о цине, я не думал, что он будет блокироваться. – nathan

15

Нет стандартного способа проверить, будет ли блокироваться getline. Вы можете использовать:

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

, чтобы увидеть, сколько символов, безусловно, доступны, прежде чем операция чтения может блокировать, но вы должны прочитать символы один за другим до повторной проверки in_avail, поскольку нет никакого способа узнать, в если любой из ожидающих символов является новой линией или фактическим концом потока. A getline вызов может блокироваться, если это не так.

Обратите внимание, что хотя если in_avail() возвращает постовое число, гарантируется, что до конца потока будет доступно как минимум много символов, обратное неверно. Если in_avail() возвращает ноль, все равно могут быть доступны символы, и поток может не блокироваться немедленно.

+2

Это не очень хорошо работает с MSVC 2013. Кажется, что оно возвращает положительное значение, даже когда поток не закрыт и вход не доступен. Я не буду тратить время на тестирование, но я определенно думаю, что он гнилой. –

+4

«Я определенно думаю, что он гнилой». - Что, MSVC? ;-) – DevSolar

0

В чем проблема, которую вы пытаетесь решить, избегая блокировки чтения здесь?

Несомненно, вы можете использовать poll или select, чтобы узнать, есть ли данные для чтения на stdin (часто fd 0 в системах unix).

Альтернативно вы можете создать второй поток для ввода-вывода и просто заблокировать его, чтобы продолжить нормальную обработку в основном потоке.

+1

, если я использую второй поток, поскольку я знаю, что есть проблема в убийстве потока, поэтому лучше жить до конца приложения. Имеет ли это смысл? –

1

Первым может быть вызов kbhit() перед чтением. Вероятно, не портативные и таят в себе опасность ...

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

using namespace std; 


char buffer[128]; 

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

Этот код может помочь вам проверить наличие данных в stdin без блокировки:

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

Если stdin имеют некоторые данные - не забудьте чтобы вернуть позицию в начало.

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

Вы можете прочитать все данные, в том числе \0 (может быть больше, чем один) в конце буфера:

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

или построчно:

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

Этот код работает в MSVC и gcc (Ubuntu)