Есть ли элегантный способ запустить событие, когда символы доступны из System.in
? Я бы хотел избежать опроса InputStream.available()
.
Как асинхронно читать стандартный ввод?
Ответы (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);
Конечно... запустите поток, который блокируется на входе, а затем вызывает ваш метод события, когда он что-то получает.
Вообще говоря:
Если у вас уже запущен реактор событий, создайте поток и заблокируйте его на read()
. Когда будут доступны данные, пусть этот поток поставит в очередь событие для обработки реактором. Если вы не можете этого сделать, большинство реакторов событий предоставляют метод InvokeLater
или CallLater
для запуска некоторого кода в потоке обработки событий.
После уведомления или планирования вызова функции вернитесь к блокировке read()
.
Если вам нужно что-то элегантное, вы можете легко реализовать ObservableInputStream
, который принимает Listener
, который получает предупреждение о доступности данных, но вам придется реализовать его с помощью внутреннего потока, который периодически проверяет данные и вызывает прослушиватель на всякий случай.
Подумайте о том, что потоки не должны использоваться как объекты, которые отправляют небольшие пакеты, а непрерывный поток байтов, поэтому этот подход будет работать только в том случае, если данные, передаваемые во входной поток, не поступают слишком часто. (иначе он продолжал бы вызывать слушателя вволю). Кроме того, вам придется позаботиться о согласованности, если данные поступают, когда что-то уже доступно, и слушатель предупрежден, тогда что-то может занять все байты (которые вы должны поместить во временный буфер), но если только что поступило больше данных, вы должны решить, как обращаться (отдать его вместе с буфером, поместить в буфер и снова вызвать прослушиватель и т. д.)