Как асинхронно читать стандартный ввод?

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


person Tony R    schedule 23.11.2010    source источник
comment
Обратите внимание, что System.in буферизуется строками, поэтому вы не можете читать одно нажатие клавиши за раз. Если вам нужно интерфейсное приложение, вам нужен графический интерфейс.   -  person Peter Lawrey    schedule 24.11.2010


Ответы (4)


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

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

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

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);
person aioobe    schedule 23.11.2010

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

person JOTN    schedule 23.11.2010

Вообще говоря:

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

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

person slezica    schedule 23.11.2010

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

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

person Jack    schedule 23.11.2010