如何异步读取标准输入(stdin)?

3
有没有一种优雅的方式在从System.in接收到字符时触发事件?我想避免轮询InputStream.available()

请注意,System.in是行缓冲的,因此您无法一次读取一个按键。如果您想要一个界面应用程序,您需要拥有一个GUI。 - Peter Lawrey
5个回答

4
你需要创建一个单独的线程,该线程会在read函数中阻塞,直到有可用数据。
如果你不希望实际读取输入,你需要使用内部缓冲区对其进行包装,将数据读入缓冲区,然后在被要求提供输入时,从缓冲区返回数据。
你可以这样解决:
InputStream stdin = System.in;

// Create a wrapper (with it's own dedicated read-thread)
MyListenableInputStream listenableInputStream =
        new MyListenableInputStream(stdin);

// Update System.in with something more useful.
System.setIn(listenableInputStream);

2

当然可以...开启一个线程,在输入上阻塞并在获取到数据后调用您的事件方法。


0

总的来说:

如果您已经有一个事件反应器在运行,请创建一个线程并让它阻塞在read()上。当有数据可用时,让该线程将一个事件加入队列以供反应器处理。如果您无法这样做,大多数事件反应器都提供了InvokeLaterCallLater方法,供您在事件处理线程中运行一些代码。

在通知或调度函数调用后,返回到阻塞在read()上。


0
如果您想要实现优雅的代码,可以轻松地实现一个ObservableInputStream,它接受一个Listener,并在数据可用时发出警告,但是您将不得不使用内部线程来定期检查数据并在需要时调用Listener。
请注意,流不应该被用作发送小数据包的对象,而应该是连续的字节流,这就是为什么这种方法只适用于输入流中给出的数据没有实际到达太频繁(否则它会不断地调用Listener)。此外,您还需要关心一致性,如果在已经有可用数据并且Listener已被警告时有新数据到达,则某些内容可能会获取所有字节(应将其放置在临时缓冲区中),但是如果有更多数据刚刚到达,则您应该决定如何处理(与缓冲区一起提供,或将其放入缓冲区并再次调用Listener等)。

0
new Thread(){

   public void run() {
      while(System.in.get()){
   }

}.start();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接