简体   繁体   中英

Flush/Clear System.in (stdin) before reading

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?

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.

这对我有用

System.in.read(new byte[System.in.available()])

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?

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();

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.

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

The best practice (that I've found) when dealing with terminals (aka. the console) is to deal with i/oa line at a time . So the ideal thing to do is get the entire line of user input, as a string , and then parse it as you see fit . Anything else is not only implementation specific, but also prone to blocking.

Scanner sc = new Scanner(System.in);
String line = "";

while (true) {
    System.out.println("Enter something...");

    try {
        line = sc.nextLine();
        //Parse `line` string as you see fit here...
        break;
    } catch (Exception e) {}
}

I include the while & try/catch blocks so that the prompt will loop infinitely on invalid input.

You can try:

System.in.skipNBytes(System.in.available());

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM