Как асинхронно читать stdin? - PullRequest
2 голосов
/ 24 ноября 2010

Есть ли элегантный способ вызвать событие, когда символы доступны из System.in? Я хотел бы избежать опроса InputStream.available().

Ответы [ 5 ]

3 голосов
/ 24 ноября 2010

Вы должны будете создать отдельный поток, который блокирует чтение, пока что-то не станет доступным.

Если вы не хотите фактически использовать входные данные, вам придется обернуть его внутренним буферомпрочитайте в буфер, кричите и, когда вас попросят ввести, верните данные из буфера.

Вы можете решить это так:

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 голосов
/ 24 ноября 2010

Конечно ... запустить поток, который блокирует входные данные, а затем вызывает метод события, когда он что-то получает.

0 голосов
/ 24 ноября 2010

Если вы хотите что-то элегантное, вы можете легко реализовать ObservableInputStream, который принимает Listener, который получает предупреждение о доступности данных, но вам придется реализовать его с внутренним потоком, который периодически проверяет данные и вызывает слушателя вcase.

Подумайте о том, что потоки не должны использоваться в качестве объекта, отправляющего небольшие пакеты, а представляют собой непрерывный поток байтов, поэтому этот подход будет работать только в том случае, если данные, которые передаются на входПоток фактически не прибывает слишком часто (иначе это продолжало бы вызывать слушателя ad libitum).Кроме того, вам придется позаботиться о согласованности, если данные поступают, когда что-то уже доступно, и слушатель получает предупреждение, тогда что-то может занять все байты (которые вы должны поместить во временный буфер), но если есть еще данные, которые только что поступили, вы должнырешить, как обрабатывать (дать его вместе с буфером, поместить в буфер и снова вызвать слушателя и т. д.)

0 голосов
/ 24 ноября 2010

В целом:

Если у вас уже запущен реактор событий, создайте поток и включите его в read(). Когда будут доступны данные, пусть этот поток поставит в очередь событие для обработки реактора. Если вы не можете сделать это, большинство событийных реакторов предоставляют метод InvokeLater или CallLater, чтобы вы могли запустить некоторый код в потоке обработки событий.

После уведомления или планирования вызова функции вернитесь к блокировке на read().

0 голосов
/ 24 ноября 2010
new Thread(){

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

}.start();
...