Java如何处理这个程序中的输入字符?缓冲区是什么样的?

问题描述 投票:0回答:1

这个 Java 程序如何工作以及它的输出是什么?

我正在开发一个 Java 程序,该程序会循环直到输入字母

S
。这是代码:

// Loops until the letter S is entered
class ForTest {
    public static void main(String[] args) 
            throws java.io.IOException {

        int i;
        char x;
        System.out.println("Enter 'S' to stop.");

        for(i = 0; (x = (char) System.in.read()) != 'S'; i++) {
            System.out.println("Iteration " + i + ", read character: " + x);
        }
    }
}

我的问题

为什么即使我只输入一个字符(本例中为 L),程序也会显示额外的迭代?

对于像

"h"
这样的单个字符输入,我希望输出是:

Iteration 0, read character: h

但相反,我得到:

Iteration 0, read character: h

Iteration 1, read character:

Iteration 2, read character: 

提前致谢!我是 Java 新手,并试图了解在这种情况下事情是如何工作的。

我尝试在循环中打印字符,但最后 2 个字符似乎是空格

java
1个回答
0
投票

默认情况下,java 终端处于所谓的“cooked”模式。熟食模式可以做很多事情。其中之一是,在用户按下 Enter 键之前,不会有任何输入实际发送到您的

System.in

换句话说,如果您编写这个非常简单的 Java 应用程序:

void main(String[] args) {
  while (true) {
    int c = System.in.read();
    if (c == -1) break;
    System.out.println("CharCode: " + c + " which is character '" + ((char) c) + "'");
  }
}

然后你运行它并键入,在击键之间有足够的时间,“h”,“e”,“l”,“l”,“o”,(输入键),然后你的java应用程序不会打印任何内容直到您按下 Enter 键,然后一口气完成所有 6 到 7 个击键。 h、e、两个 ls、一个 o 和“新行”,即代码 13(您可以将其写为

13
'\n'
0x0D
- 它们都表示“13”,并且有因此,这 3 种形式之间绝对没有任何区别 - 无论哪一种使您的代码最具可读性,毫无疑问,在大多数操作系统上都是
'\n'
),但往往是 2 个字符(即 10 后面跟着 13,更易读) ,
\r
,然后是
\n
)。

这大概就是您的示例中发生的情况:您按了 h,,然后按了 Enter,这本身也是一个字符。你在 Windows 上,所以实际上是 2 个字符,因此总共 3 次迭代。一根用于

'h'
,一根用于
'\r'
,一根用于
'\n'

我想一次读取一个字符

哦。非常困难。您需要首先告诉操作系统进入未煮过的模式,该模式取决于操作系统,并且java没有烘焙方法来执行此操作,您需要发送适合您的操作系统的魔术序列,并且(2)未煮过的模式有很多缺点。例如,您的输出如下所示:

Enter your name: Joe
                 Hi Joe!

即'println' 不一定再将光标移回原处,而未煮熟的模式到底有多奇怪取决于操作系统。

如果你想要生的,你需要一个库来简化它,它们确实存在。例如灯笼。但是,实际上,如果您想要更高级的“UI”,而不仅仅是“输入内容并按 Enter”,那么您可能一开始就不应该拥有基于文本的界面,而应将其设为图形界面(通过 swing 或 javafx 或通过执行过去十年每个人都在做的事情,并为其制作了一个网络界面)。

不,我一次读一本就可以了

太棒了!然后要读取文本输入,您可能需要这个:

void main(String[] args) {
  Scanner s = new Scanner(system.in);
  s.useDelimiter("\\R");

  System.out.println("Hi there! What is your full name?");
  String fullName = s.next();
  System.out.println("Good to meet you, " + fullName + "!");

  System.out.println("How old are you?");
  int age = s.nextInt();
}

注意,有一个

nextLine
方法。不要使用它。它按照其规格说明执行操作,但这不是您所期望的。
next()
已经读取了一整行(因为我们修复了分隔符)。

注意:对于未来的读者 - 这个答案很快就会(几年的时间)过时,正确的答案会变成“使用

java.io.IO
中的静态方法”。由于这仍处于预览阶段,因此它(还)不是这个问题的适当答案。

注意:terminal 默认处于“cooked”模式。如果您将其他任何东西连接到

System.in
,那就不会了。例如,如果您运行
java yourapp.Application <someFile
,则
System.in()
不会逐行缓冲;正如人们所期望的那样,您一次只会获得一个角色。缓冲的事情根本不是由java 完成的; java 只是将
System.in
视为一个简单的管道,并且不会缓冲它,除非您要求将其包装在
BufferedInputStream
中。操作系统/终端正在执行此操作。您可以要求它停止执行此操作 - 但它会停止执行更多操作 - 这称为“请求未煮过的模式”。你..不想要那样,它不适合初学者。

© www.soinside.com 2019 - 2024. All rights reserved.