简体   繁体   English

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

[英]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.在工作中,我们有 5 个 RFID 读取器连接到运行 Linux 的 PC。读取器都被识别为键盘,并将它们的输入(它们从芯片读取的内容)作为键输入事件序列发送。 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.为了能够告诉哪个读者发送什么序列,我正在对/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.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 )).问题在于,RFID 阅读器生成的发送键盘事件仍然“在”stdin 中,当我尝试通过ScannerSystem.in读取时(这次输入应该由普通键盘生成),我首先从读者那里获取“待定”输入(由 10 个十六进制数字和一个换行符 ( \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 ).但是在 stdin 上不允许查找( 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()估计不够(之后仍然在 stdin 中)。

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?有人有更多想法吗?

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. 在这种情况下有效,表示十进制整数。

这对我有用

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? 如果您知道待处理的数据以\\n结尾,那么为什么不查找直到找到呢?

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. 由于我对您使用的RFID扫描仪不熟悉,因此无法提供更多帮助,但这是我的建议。

You could do this with multiple threads. 您可以使用多个线程来执行此操作。

  1. Your real application reads from a PipedInputStream that is connected to a PipedOutputStream 您的实际应用程序从连接到PipedOutputStream的PipedInputStream读取
  2. You need to have one thread reading from System.in continuously. 您需要连续从System.in读取一个线程。 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. 只要实际应用程序对System.in的数据(由布尔标志表示)不感兴趣,该线程就会丢弃它读取的所有内容。 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. 但是,当实际应用程序设置标志以指示它对来自System.in的数据感兴趣时,该线程会将其读取的所有数据发送到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 这样, System.in的数据将始终自动刷新/清除

The best practice (that I've found) when dealing with terminals (aka. the console) is to deal with i/oa line at a time . 处理终端设备 (又称控制台)时(我发现)的最佳做法是一次处理i / oa线路 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. 我加入了whiletry/catch块,以便提示将在无效输入时无限循环。

You can try:你可以试试:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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