如何在 Java 中从控制台读取单个字符(当用户键入它时)?

How to read a single char from the console in Java (as the user types it)?

提问人:victor hugo 提问时间:7/1/2009 最后编辑:Thomas Ahlevictor hugo 更新时间:10/7/2021 访问量:164616

问:

有没有一种简单的方法可以在用户在 Java 中键入单个字符时从控制台读取它?可能吗?我已经尝试了这些方法,但它们都在等待用户按回车键:

char tmp = (char) System.in.read();
char tmp = (char) new InputStreamReader(System.in).read ();
char tmp = (char) System.console().reader().read();           // Java 6

我开始认为,在按下回车键之前,System.in 不知道用户输入。

Java 输入 控制台

评论


答:

68赞 Chris W. Rea 7/1/2009 #1

您要做的是将控制台置于“原始”模式(绕过行编辑,无需输入键),而不是“熟”模式(需要使用回车键进行行编辑)。在 UNIX 系统上,“stty”命令可以更改模式。

现在,关于 Java...请参阅 Python 和 Java 中的非阻塞控制台输入。摘录:

如果您的程序必须基于控制台, 你必须把你的终端换掉 从行模式转换为字符模式,以及 记得在你之前恢复它 程序退出。没有便携式 在整个操作中执行此操作的方法 系统。

其中一个建议是使用 JNI。同样,这不是很便携。线程末尾的另一个建议,与上面的帖子一样,是考虑使用 jCurses

评论

4赞 Ryan Fernandes 7/1/2009
JCurses 也不是很便携......摘自 JCurses README:“JCurses 由两部分组成:平台独立部分和平台依赖部分,它由一个原生共享库组成,使原始输入和输出操作可用于第一部分。
6赞 Antoniossss 10/20/2017
@RyanFernandes对我来说听起来很可移植 - 可以在多个系统上运行的单个工具(使用不同的依赖项)
30赞 nes1983 7/30/2011 #2

您需要将控制台置于原始模式。没有内置的独立于平台的方式可以到达那里。不过,jCurses 可能很有趣。

在 Unix 系统上,这可能有效:

String[] cmd = {"/bin/sh", "-c", "stty raw </dev/tty"};
Runtime.getRuntime().exec(cmd).waitFor();

例如,如果要考虑击键之间的时间,下面是实现该目标的示例代码。

评论

0赞 MrSmith42 10/21/2015
在 Linux 下对我来说工作正常
7赞 Kelvin 5/9/2017
也可以在Mac上工作。您可能想提到,当程序需要恢复到缓冲模式时,应该在程序退出之前运行。stty cooked </dev/tty
18赞 rustyx 10/2/2011 #3

没有可移植的方法来从 Java 控制台读取原始字符。

上面介绍了一些与平台相关的解决方法。但要真正便携,您必须放弃控制台模式并使用窗口模式,例如 AWT 或 Swing。

23赞 Christian d'Heureuse 5/3/2015 #4

我编写了一个 Java 类 RawConsoleInput,它使用 JNA 来调用 Windows 和 Unix/Linux 的操作系统函数。

  • 在 Windows 上,它使用 和 来自 msvcrt.dll。_kbhit()_getwch()
  • 在 Unix 上,它用于将控制台切换到非规范模式,检查数据是否可用并从控制台读取字节。A 用于将字节转换为字符。tcsetattr()System.in.available()System.in.read()CharsetDecoder

它支持无阻塞输入和混音原始模式和正常线路模式输入。

评论

0赞 5/15/2016
这经过了多大程度的测试/压力测试?
2赞 Christian d'Heureuse 5/16/2016
@QPaysTaxes 对于控制台输入,压力测试很困难。我认为,在这种情况下,在各种环境(不同的 Windows/Linux 版本、64/32 位、通过 SSH 的 Linux、Telnet、串行端口或桌面控制台等)中对其进行测试会更为重要。到目前为止,我只在我的私人测试工具中使用它。但与其他解决方案(如使用 Jansi 的 JLine2)相比,源代码相对较小。因此,没有太多可能出错的地方。我写了它,因为 JLine2 不支持没有阻塞的单字符输入。
0赞 5/16/2016
这就是我所说的压力测试的意思——它可能是错误的词;我的错。总之,不错!我偷了^H^H^H^H^H^H^H^H^H在我的一个学校项目中,它帮助了很多人。
0赞 Igor 8/25/2016
嘿 - 这门课看起来很棒。但是:我无法让它工作。我应该如何使用它?在我按 CTRL+D(在 Linux 上)之前,我遇到了 System.in 阻塞,现在我阅读了有关控制台模式等的信息。我认为您的 RawConsoleInput 是我正在寻找的 - 但我该如何使用它?
1赞 WaterGenie 9/19/2020
@M.E.除了 RawConsoleInput.java 之外,还必须添加 JNA jar。此外,JNA 在版本 5 中弃用了 Pointer.SIZE,因此我们还需要将其替换为 on line 170。Native.POINTER_SIZE
14赞 Pod 11/29/2017 #5

使用 jline3

例:

Terminal terminal = TerminalBuilder.builder()
    .jna(true)
    .system(true)
    .build();

// raw mode means we get keypresses rather than line buffered input
terminal.enterRawMode();
reader = terminal .reader();
...
int read = reader.read();
....
reader.close();
terminal.close();

评论

0赞 RawToast 4/15/2018
我发现基于 RawConsoleInput 的解决方案在 MacOS High Sierra 上不起作用;但是,这非常有效。
0赞 lepe 6/26/2018
JLINE几乎拥有创建交互式控制台/终端系统所需的一切。它在 Linux 中运行良好。有关更完整的示例,请查看:github.com/jline/jline3/blob/master/builtins/src/test/java/org/... 。它具有自动完成、历史记录、密码掩码等功能。
1赞 ewing 4/10/2021 #6

我已经使用 jcurses 完成了它......

import jcurses.system.InputChar;
import jcurses.system.Toolkit;

//(works best on the local machine when run through screen)
public class readchar3 {
    public static void main (String[] args)
        {
            String st;
            char ch;
            int i;
            st = "";
            ch = ' ';
            i = 0;
            while (true)
                {
                        InputChar c = Toolkit.readCharacter();
                    ch = c.getCharacter();
                    i = (int) ch;
                    System.out.print ("you typed " + ch + "(" + i + ")\n\r");
                    // break on '#'
                    if (ch == '#') break;
                }
            System.out.println ("Programm wird beendet. Verarbeitung kann beginnen.");
        }
}
0赞 simu XD 10/7/2021 #7

看到这个

它从 c 调用 _getch() 函数来读取单个字符,而无需按 Enter 键