Почему мы не можем читать один символ за раз из System.in?

Программа ниже печатает каждый символ, записанный на стандарте, но только после того, как была написана новая строка (по крайней мере, в моей системе!).

public class Test { public static void main(String[] args) throws java.io.IOException { int c; while ((c = System.in.read()) != -1) System.out.print((char) c); } } 

Это мешает людям писать такие вещи, как «Нажать любую клавишу, чтобы продолжить», и заставляет что-то вроде «Нажмите enter, чтобы продолжить».

  • В чем причина этого?
  • Является ли это ограничением Java?
  • Является ли это поведение зависящим от системы (я на Ubuntu)? Как это работает на Mac? Окна?
  • Это зависит от конкретного терминала, в котором я запускаю приложение? (Для меня это ведет себя как в Eclipse и в гном-терминале)
  • Есть ли обходной путь?

В чем причина этого?

Большинство терминалов по умолчанию буферизируется по строке, Java не получает ввод до новой строки.

Является ли это ограничением Java?

Некоторые древние терминалы могут иметь только вход с линейной буферизацией; хотя в большинстве современных терминалов должно быть возможно отключить буферизацию.

Является ли это поведение зависящим от системы (я на Ubuntu)? Как это работает на Mac? Окна?

Да.

Это зависит от конкретного терминала, в котором я запускаю приложение? (Для меня это ведет себя как в Eclipse и в гном-терминале)

Да.

Есть ли обходной путь?

Существуют хаки для платформы. curse в Linux и Unix-подобных платформах и getch () в Windows. Я не знаю о кросс-платформенном способе.

related : Почему «Нажмите любую клавишу, чтобы продолжить» – это плохая идея:

alt text

Я на Ubuntu

Есть ли обходной путь?

 Runtime.getRuntime().exec("stty -icanon min 1").waitFor(); 

И после этого все прочтения System.in в том же процессе будут читать 1 символ, не дожидающий EOL.

см. мой ответ в эквивалентной функции на «_getch ()» в Java?

 public static void getCh() { final JFrame frame = new JFrame(); synchronized (frame) { frame.setUndecorated(true); frame.getRootPane().setWindowDecorationStyle(JRootPane.FRAME); frame.addKeyListener(new KeyListener() { public void keyPressed(KeyEvent e) { synchronized (frame) { frame.setVisible(false); frame.dispose(); frame.notify(); } } public void keyReleased(KeyEvent e) { } public void keyTyped(KeyEvent e) { } }); frame.setVisible(true); try { frame.wait(); } catch (InterruptedException e1) { } } 

public static void getCh() { final JFrame frame = new JFrame(); synchronized (frame) { frame.setUndecorated(true); frame.getRootPane().setWindowDecorationStyle(JRootPane.FRAME); frame.addKeyListener(new KeyListener() { public void keyPressed(KeyEvent e) { synchronized (frame) { frame.setVisible(false); frame.dispose(); frame.notify(); } } public void keyReleased(KeyEvent e) { } public void keyTyped(KeyEvent e) { } }); frame.setVisible(true); try { frame.wait(); } catch (InterruptedException e1) { } }

}

  • Очистить stdin перед чтением
  • Можно ли установить тайм-аут для std :: cin?
  • Запуск внешней программы с перенаправленным stdin и stdout из Java
  • Обнаруживать, является ли stdin терминалом или трубой?
  • Использование fflush (stdin)
  • Использование fseek с указателем файла, указывающим на stdin
  • Как отправить ввод на консоль, как если бы пользователь печатал?
  • запустить exe / process с stdin stdout и stderr?
  • Как определить, была ли перенаправлена ​​Console.In (stdin)?
  • Как заставить ssh получить пароль от stdin
  • Чтение из stdin flush stdout?
  • Давайте будем гением компьютера.