【问题标题】:Parse input without using anything but System.in.read()解析输入而不使用 System.in.read()
【发布时间】:2012-10-18 01:56:27
【问题描述】:

我很难找到有关 System.in.read(); 工作原理的详细信息,也许有人可以帮助我。似乎 Scanner 会更好,但我不允许使用它。

我被分配了一个任务,我应该以 Boolean-Operator-Boolean 形式读取控制台用户输入,例如T^F 或 T&T 通过System.in.read() 并简单地打印语句返回的内容。

普通人可能会使用不同的方法,但作业明确指出只允许使用 System.in.read()System.out.println()

这是我解决它的尝试:

import java.io.*;

public static void main(String[] args) {

  String error = "Reading error, please use T or F";

  boolean a = true;  //char: 84 or 116 for T and t
  boolean b = false; //char: 70 or 102 for F and f
  int userChar1;
  int userOperator;
  int userChar2;
  int chosenOperator = 0;

  try {

    //Get first char
    System.out.println("Enter the first value (T or F):");
    userChar1 = System.in.read();

    if((userChar1==84)||(userChar1==116)) { // T or t
      a = true;
    } else if ((userChar1==70)||(userChar1==102)) { // F or f
      a = false;
    } else {
      System.out.println(error);
    }


    //Get second char
    System.out.println("Select an operator:  &  |  ^");
    userOperator = System.in.read();

    if(userOperator==38) { // &
      chosenOperator = 0;
    } else if (userOperator==124) { // |
      chosenOperator = 1;
    } else if (userOperator==94) { // ^
      chosenOperator = 2;
    } else {
      System.out.println(error);
    }


    //Get third char 
    System.out.println("Enter the second value:");
    userChar2 = System.in.read();
    System.in.close();
    if((userChar2==84)||(userChar2==116)) {
      b = true;
    } else if ((userChar2==70)||(userChar2==102)) {
      b = false;
    } else {
      System.out.println(error);
    }


    //Figure out result
    boolean result;
    switch (chosenOperator) {
    case 0:
      result = a&b;   
    case 1:
      result = a|b;
    case 2:
      result = a^b;

      System.out.println(result);

    }

  } catch(IOException e) {

  }
}

执行此代码会使控制台在第一个System.in.read() 之后等待用户输入,并让它正确检查字符输入。然而,在那之后,所有后续的System.in.read() 都将被忽略并且程序终止。

我发现了一段使用System.in.close() 的代码,所以仍然不知道在每个System.in.read() 之后我将其拼接到的具体方法是什么。这会导致程序在调用 System.in.close() 之后的第一个 System.in.read() 时终止。

那么,到底发生了什么?如何正确使用System.in.read()

【问题讨论】:

  • 如果你坚持使用read(),那么你将不得不阅读两次并且只使用第一个结果作为输入。

标签: java input io


【解决方案1】:

问题不在于 System.in.read(),而在于控制台。 控制台通常是缓冲的,这意味着数据仅在按下回车键后才会发送到您的程序(因此可由 System.in.read() 读取)。 因此,您必须将控制台切换到无缓冲模式,但没有可移植的方式来执行此操作,因为有很多不同类型的控制台(unix shell、cmd 窗口、Eclipse 控制台等)。
如果不允许使用 System.in.read() 和 System.out.println() 方法以外的任何方法,则必须让用户在一行中输入完整的术语,然后按 Enter 键,然后您可以处理字符输入,例如:

public static void main(String[] args) throws IOException {
    boolean a = true; // char: 84 or 116 for T and t
    boolean b = false; // char: 70 or 102 for F and f
    int userChar1;
    int userOperator;
    int userChar2;

    System.out.println("Please enter the term, e.g. T&F:");

    userChar1 = System.in.read();
    userOperator = System.in.read();
    userChar2 = System.in.read();

    a = userChar1 == 'T' || userChar1 == 't';
    b = userChar2 == 'T' || userChar1 == 't';

    switch (userOperator) {
    case '&':
        System.out.println(a & b);break;
    case '|':
        System.out.println(a | b);break;
    case '^':
        System.out.println(a ^ b);break;
    default:
        System.out.println("unknow operator");
    }
}

【讨论】:

  • 我想我理解您对缓冲输入的解释,但是为什么在按下键之前保留数据传输会阻止控制台在不同场合解析输入?似乎控制台输入在 System.in.read() 被调用后立即停止缓冲,因为它在我的初始代码中进一步跳过了 System.in.read()。这不是发生的事情,是吗?
  • 您的初始代码没有跳过进一步的 System.in.read() 调用。如果您进入第一个提示“t&f”然后按回车,代码将 1)读取第一个字符“t”,2)打印下一个提示,3)读取第二个字符“&”(无需等待),4)打印下一个提示,5)读取字符“f”(无需等待),6)打印结果,7)退出
  • 哦哦哦。我知道了。谢谢你解释。
【解决方案2】:

请看以下部分代码:

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

String input = null;

//  read the input from the command-line; need to use try/catch with the
//  readLine() method
try {
input = br.readLine();
} catch (IOException e) {
      System.out.println("IO error trying to read your input!");
      System.exit(1);
}
System.out.println("your input: "+input);

如果你不允许使用bufferReader,我建议你看看bufferReader的源代码。

【讨论】:

    【解决方案3】:

    就我个人而言,运行你的代码没有问题,但它有一些奇怪的效果,我必须研究一下。

    这种方法(使用System.in.read())的主要问题是,当用户输入某个字符时,他必须按enter,因此您有2个字符而不是您期望的1个字符——用户输入的第一个字符(假设您的情况是 T 或 F)和换行符。

    我设法让您的代码进行了细微的更改。您需要调用 read() 方法的重载版本 -- read(byte[] b) 读取为 some number of bytes from the input stream and stores them into the buffer array

    这是您的代码的第一部分,已修改:

    byte[] input = new byte[10];
    System.out.println("Enter the first value (T or F):");
    System.in.read(input);
    userChar1 = input[0];
    if ((userChar1 == 84) || (userChar1 == 116)) { // T or t
        a = true;
    } else if ((userChar1 == 70) || (userChar1 == 102)) { // F or f
        a = false;
    } else {
        System.out.println(error);
    }
    

    注意,我们不关心 read() 返回什么,我们只关心 input 数组中的第一个字符。其余代码以相同方式修改,您甚至可以使用相同的缓冲区数组 (input) 并查询第 0 个元素。

    【讨论】:

    • 唷,这是一种更清洁的方法。谢谢。我仍然不明白 System.in.read() 究竟做了什么,因为 .close() 似乎终止了程序并再次调用 .read() 进一步向下文件被忽略并跳过。这是微不足道的,因为该方法很少直接使用,还是我做错了什么?
    • @Jake close() 关闭流,因此在此调用后无法对其进行任何操作。不会跳过对read() 的第二次调用,它只返回 10(你可以自己检查),它代表换行符 \n。我还没有看到read() 在这种情况下被使用。当然,我更喜欢使用更强大、更容易使用的Scanner
    • 哦,就是这样。我想我现在明白了。感谢您的耐心和解释!
    猜你喜欢
    • 1970-01-01
    • 2021-10-23
    • 1970-01-01
    • 2014-05-19
    • 1970-01-01
    • 2017-07-02
    • 2011-07-24
    • 1970-01-01
    • 2021-01-06
    相关资源
    最近更新 更多