Linux 读取前刷新/清除 System.in (stdin)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18273751/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-07 00:34:07  来源:igfitidea点击:

Flush/Clear System.in (stdin) before reading

javalinuxstdinkeyboard-events

提问by Lukas Knuth

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/XXand get their input this way.

在工作中,我们有 5 个 RFID 阅读器连接到运行 Linux 的 PC。阅读器都被识别为键盘,并将他们的输入(他们从芯片读取的内容)作为键输入事件序列发送。为了能够知道哪个读者发送了什么序列,我正在做一个原始阅读/dev/input/XX并以这种方式获取他们的输入。

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.invia 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)).

问题是,由 RFID 阅读器生成的发送键盘事件仍然“在”标准输入中,当我尝试从System.invia读取时Scanner(这次输入应该由普通键盘生成),我首先得到“pending " 来自阅读器的输入(由 10 个十六进制数字和一个换行符 ( \n) 组成)。

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

现在,问题是:如何从标准输入中刷新所有这些“待处理”输入,然后从键盘读取我真正想要的内容?

I tried:

我试过:

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

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

但是在标准输入上不允许搜索(skip抛出一个IOException)。

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

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

available()估计不够(之后仍然在标准输入中)。

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

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

hasNextLine()永远不会成为false(打印永远不会执行)。

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?

有人有更多想法吗?

采纳答案by Lukas Knuth

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

根据@Joni的建议,我把它放在一起:

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.

这会丢弃标准输入中已经“待处理”的数据,并等待输入有效数据。有效,在此上下文中,表示十进制整数。

回答by William Morrison

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.

由于我不熟悉您正在使用的 RFID 扫描仪,因此我无法提供更多帮助,但这就是我的建议。

回答by Joni

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

没有内置的可移植方式来刷新输入流中的数据。如果您知道待处理的数据以以下方式结束,\n为什么在找到它之前不阅读呢?

回答by Lukas Knuth

This worked for me

这对我有用

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

回答by Erwin Bolwidt

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.incontinuously. 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.
  1. 您的真实应用程序从连接到 PipedOutputStream 的 PipedInputStream 读取
  2. 您需要System.in连续读取一个线程。只要实际应用程序对来自 System.in 的数据(由布尔标志表示)不感兴趣,该线程就会丢弃它读取的所有内容。但是,当实际应用程序设置标志以表明它对来自 System.in 的数据感兴趣时,该线程会将它读取的所有数据发送到 PipedOutputStream。
  3. 您的实际应用程序打开该标志以表明它对数据感兴趣,并在它不再对数据感兴趣时清除该标志。

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

这样,来自的数据System.in总是自动刷新/clead

回答by Manohar Reddy Poreddy

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

回答by veganaiZe

The best practice (that I've found) when dealing with terminals(aka. the console) is to deal with i/o a 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.

处理终端(又名控制台)时的最佳实践(我发现)是一次处理 i/oa 线。因此,理想的做法是获取用户输入的整行,作为 string,然后按照您认为合适的方式对其进行解析。其他任何东西不仅是特定于实现的,而且容易阻塞。

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/catchblocks so that the prompt will loop infinitely on invalid input.

我包含while&try/catch块,以便提示将在无效输入上无限循环。