Flush/Clear System.in (stdin) before reading

2019-01-20 16:10发布

At work, we have 5 RFID readers attached to a PC running Linux. The readers are all recognized as keyboards and send their input (what they read form the Chip) as an key-input-event sequence. To be able to tell which reader send what sequence, I'm doing a raw-read over /dev/input/XX and get their input this way.

The problem with this is, that the send keyboard-events generated by the RFID readers are still "in" stdin and when I try to read from System.in via Scanner (input should be generated by a normal keyboard this time), I first get the "pending" input from the readers (which consists of 10 Hex-decimal digits and a newline (\n)).

Now, the question is: How can I flush all these "pending" input's from stdin and then read what I really want from the keyboard?

I tried:

System.in.skip(System.in.available());

But seek is not allowed on stdin (skip throws an IOException).

for (int i = 0; i < System.in.available(); i++){
  System.in.read();
}

But available() doesn't estimate enough (still stuff in stdin afterwards).

Scanner scanner = new Scanner(System.in);
while (scanner.hasNextLine()){
  scanner.nextLine();
}
System.out.println("Clean!");

But hasNextLine() never becomes false (the print never executes).

BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String line;
while ((line = in.readLine()) != null);
System.out.println("Clean!");

Same as above.

Anyone with any more ideas?

6条回答
【Aperson】
2楼-- · 2019-01-20 16:55

You could do this with multiple threads.

  1. Your real application reads from a PipedInputStream that is connected to a PipedOutputStream
  2. You need to have one thread reading from System.in continuously. As long as the real application is not interested in the data coming from System.in (indicated by a boolean flag), this thread discards everything that it reads. But when the real application sets the flag to indicate that it is interested in the data coming from System.in, then this thread sends all the data that it reads to the PipedOutputStream.
  3. Your real application turns on the flag to indicate that it is interested in the data, and clears the flag when it is no longer interested in the data.

This way, the data from System.in is always automatically flushed/clead

查看更多
地球回转人心会变
3楼-- · 2019-01-20 16:59

This worked for me

System.in.read(new byte[System.in.available()])
查看更多
Melony?
4楼-- · 2019-01-20 17:05

Devices usually send data using a well defined protocol which you can use to parse data segments.

If I'm right, discard data that isn't properly formatted for the protocol. This allows you to filter out the data you aren't interested in.

As I'm not familiar with the RFID scanner you're using I can't be of more help, but this is what I suggest.

查看更多
神经病院院长
5楼-- · 2019-01-20 17:07

A related one.

I read a double, then needed to read a string.

Below worked correctly:

double d = scanner.nextDouble();
scanner.nextLine(); // consumes \n after the above number(int,double,etc.)
String s = scanner.nextLine();
查看更多
地球回转人心会变
6楼-- · 2019-01-20 17:09

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.

查看更多
你好瞎i
7楼-- · 2019-01-20 17:10

There is no built-in portable way to flush the data in an input stream. If you know that the pending data ends with \n why don't you read until you find it?

查看更多
登录 后发表回答