Flush/Clear System.In (Stdin) Before Reading

Flush/Clear System.in (stdin) before reading

Based on @Joni's advice, i put this together:

Scanner scanner = new Scanner(System.in);
int choice = 0;
while (scanner.hasNext()){
if (scanner.hasNextInt()){
choice = scanner.nextInt();
break;
} else {
scanner.next(); // Just discard this, not interested...
}
}

This discards the data that is already "pending" in stdin and waits until valid data is entered. Valid, in this context, meaning a decimal integer.

How to properly flush stdin in fgets loop

So what happens is that I have to press enter twice now. Why is this happening, and how can I fix this?

Well, that is what your code is doing - it first reads char-by-char until it finds newline. Then it calls fgets() which will... well, read until it finds a newline (probably char-by-char, but, also possibly in some other way).

You could try fflush(stdin), but that is not guaranteed to do what you want (it only gives guarantees for output buffers, not for input).

Also, you may try setbuf(stdin, NULL) which should disable buffering on standard input, so there would be nothing to flush. I tried this a few times on different systems and it worked, but documentation for this function is not 100% clear on this.

How can I clear stdin in a C progam?

To achieve what you want — reading and ignoring extra characters up to a newline if the buffer you supplied is over-filled — you need to conditionally read up to the newline, only doing so if there isn't a newline already in the input buffer that was read.

void read_string(char *s, int width)
{
if (fgets(s, width, stdin) != 0)
{
size_t length = strlen(s);
if (length > 0 && s[length-1] != '\n')
{
int c;
while ((c = getchar()) != '\n' && c != EOF)
;
}
/* Use the input data */
}
else
/* Handle EOF or error */
}

The other part of the technique is to make sure that you use a big enough buffer that it is unlikely that anyone will overflow it. Think in terms of char buffer[4096]; as an opening bid; you can increase it if you prefer. That makes it unlikely that anyone will (be able to) type enough data on a single line to overflow the buffer you provide, thus avoiding the problem.

Another option is to use POSIX getline(). It reads a line into allocated space, allocating more space until the data fits (or you run out of memory). It has at least one other major advantage over fgets() — it reports the number of characters in the line it read, which means it is not confused by null bytes ('\0', usually typed as Control-@) in the input. By contrast, you can't tell whether there was any data entered after the first null byte with fgets(); you have to assume that the input stopped at the first null byte.

Note that the simple loop shown in the question (while (getchar() != '\n');) becomes infinite if it encounters EOF before reading a newline.

How clear stdin in Python

This is a good one, I believe that if you're working on a UNIX system you should be able to clear any queued data in stdin before calling input using termios. Try something like this:

from termios import tcflush, TCIFLUSH

while True:
web_scrapping()
print ("Press ENTER: \n")
time.sleep(interval)
i, o, e = select.select( [sys.stdin], [], [], 10 )
if (i):
# Clear queue before asking for new input
tcflush(sys.stdin, TCIFLUSH)
Start()

This should make possible to have a fresh queue when calling Start. Commenting line 13 from the example below will call input submitting whatever is found in the queue at call time. Flushing the queue before the call helps to avoid that behavior:

import select
import sys
import time
from termios import TCIFLUSH, tcflush

while True:
print("Pretend I'm doing some stuff")
time.sleep(2)
i, o, e = select.select([sys.stdin], [], [], 2)
# Enters if anything has been submitted
if i:
# Clear queue before asking for new input
# commenting it will submit whathever data is queued to stdin
tcflush(sys.stdin, TCIFLUSH)
a = input("Echo: ")
print(f"your input is: {a}")
break
else:
print("Nothing found in stdin")

How to clear the stdin buffer in python when stdin is non-interactive

Thanks for your suggestions so far. Apparently this was, after all, one of those strange concurrency problems.

When I set a timeout in the select call, it works. So it seems that the buffer really has not been filled at the moment I call the select.

Does not work (same as in the question):

while select.select([sys.stdin], [], [], 0) == ([sys.stdin], [], []):
sys.stdin.read(1)

Does work:

while select.select([sys.stdin], [], [], 0.01) == ([sys.stdin], [], []):
sys.stdin.read(1)

As the things I want to read are line-based, I can read a whole line at a time with input instead of reading single characters with read though, and then the slowdown of the timeout in the while loop will not be noticeable. (There will be max. 5-10 lines in the buffer).

I am not totally satisfied with this solution as it involves waiting for an arbitrary amount of time (will 0.01 always be enough?). But on the other hand I can't think of a better solution right now as I can't influence the code writing to "my stdin".



Related Topics



Leave a reply



Submit