checking data availability before calling std::getline
I would like to read some data from a stream I have using std::getline
.
Below a sample using the std::cin
.
std::string line;
std::getline( std::cin, line );
This is a blocking function i.e. if there is no data or line to read it blocks execution.
Do you know if exists a function for checking data availability before calling std::getline
? I don't want to block.
How can I check whether the stream buffer is full of data valid for a successful call to std::getline
?
Whatever looks like the code below
if( dataAvailableInStream() )
{
std::string line;
std::getline( std::cin, line );
}
There is no standard way to verify if getline
will block. You can use:
std::cin.rdbuf()->in_avail()
to see how many characters are definitely available before a read operation may block, but you would have to read the characters one by one before re-checking in_avail
as there is no way to know in advance if any of the pending characters is a newline or the actual end of the stream. A getline
call might block if this wasn't the case.
Note that although if in_avail()
returns a postive number there are guaranteed that at least that many characters are available before the end of the stream, the converse is not true. If in_avail()
returns zero there may still be characters available and the stream might not block immediately.
The iostream
library doesn't support the concept of non-blocking I/O. I don't think there's anything in the C++ standard that does. Any good solution would likely be platform-specific. If you can use the POSIX libraries, you might look into select
. It's usually used for networking stuff, but it'll work just fine if you pass it the file descriptor for stdin.
This code can help you to check existence of data in the stdin
without blocking:
std::cin.seekg(0, std::cin.end);
int length = std::cin.tellg();
if (length < 0) return; //- no chars available
If stdin
has some data - don't forget to set the position back to the beginning.
std::cin.seekg(0, std::cin.beg);
You can then read all data including \0
(can be more than one) at the end of the buffer:
std::vector<char> s(length);
std::cin.read(s.data(), length);
or line by line:
std::string line;
while (std::cin) {
std::getline(std::cin, line);
//.....
}
This code works in MSVC and gcc (Ubuntu)
A hack could be to call kbhit() before the read. Probably not portable and fraught with danger...
#include <conio.h>
#include <iostream>
using namespace std;
char buffer[128];
if (kbhit())
{
cin.getline(buffer, sizeof(buffer));
}