【问题标题】:How to write "enter key pressed" to a stream?如何将“按下输入键”写入流?
【发布时间】:2011-02-08 16:56:53
【问题描述】:

对不起这个听起来很奇怪的标题...

我有以下情况:我希望我的 Java 程序与外部控制台交互。为了将各个命令“发送”到该控制台,我需要模拟普通控制台上的“按下回车键”。为了澄清我想要什么,假设 mysql 没有其他 API,我需要通过控制台进行交互。虽然这不是我的实际问题,但已经足够接近了。

我有以下代码:

        String command = "/usr/local/mysql/bin/mysql";
        Process child = Runtime.getRuntime().exec(command);

        StreamGobbler gobbler = new StreamGobbler(child.getInputStream());
        gobbler.start();

        BufferedWriter out = new BufferedWriter(new OutputStreamWriter(child.getOutputStream()));
        out.write("help");
        // here enter key needs to be pressed
        out.flush();
        // out.close();

如果对out.close() 的调用被执行,一切都很好。但是当然,这样我只能发送一个命令,这不是我想要的。但是如果out.close() 被省略,其他程序永远不会执行该命令。我的猜测是它仍在等待命令“完成”,这在普通控制台上可以通过按 enter 完成。 out.write(System.getProperty("line.separator")); 和 out.newLine();(相同)不能解决问题,out.write("\r\n"); 和 out.write((char) 26); (EOF) 也不能解决问题。

当然,可能是我做的完全错误(即错误的方法)。那么我会很感激一个指向正确方向的指针......

对此高度赞赏的任何帮助。

【问题讨论】:

  • 您应该使用标准输出和标准错误输出流。您在这些直播中收到了什么?
  • 你在什么系统上?您使用 Unix 路径,但尝试了 Windows EOF (Ctrl-Z = 26)? Unix EOF 是 Ctrl-D (=4),但发送肯定不是正确的。
  • @Mark Peters:对不起,我也应该为错误输出流添加一个 gobbler,但是除非out.close() 像指出的那样执行,否则两个流都不会收到任何信息。 @Sergey Tachenov:我在 Mac 上工作,Ctrl-D 也不起作用,但感谢您指出这一点。

标签: java interface process


【解决方案1】:

以下代码在使用 Java 1.6.0_23 的 Windows 7 和使用 Java 1.6.0_22 的 Ubuntu 8.04 上都可以正常工作:

public class Laj {

  private static class ReadingThread extends Thread {
    private final InputStream inputStream;
    private final String name;

    public ReadingThread(InputStream inputStream, String name) {
      this.inputStream = inputStream;
      this.name = name;
    }

    public void run() {
      try {
        BufferedReader in = new BufferedReader(
            new InputStreamReader(inputStream));
        for (String s = in.readLine(); s != null; s = in.readLine()) {
          System.console().writer().println(name + ": " + s);
        }
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }

  public static void main(String[] args) throws Exception {
    String command = "psql -U archadm arch";
    final Process child = Runtime.getRuntime().exec(command);
    new ReadingThread(child.getInputStream(), "out").start();
    new ReadingThread(child.getErrorStream(), "err").start();
    BufferedWriter out = new BufferedWriter(
        new OutputStreamWriter(child.getOutputStream()));
    out.write("\\h");
    out.newLine();
    out.flush();
    out.write("\\q");
    out.newLine();
    out.flush();
  }

}

newLine() 与编写平台行分隔符相同。正如人们所期望的那样,它会打印以“out:”开头的帮助,然后退出。如果我不发送“\q”,它不会退出(显然)但仍会打印帮助。使用“\r\n”或“\r”代替平台行分隔符对我来说不是一个好主意,因为这样的命令行实用程序通常会检测到它们没有从终端获取输入并假设它采用本机文本格式(想想“psql

【讨论】:

  • 感谢您发布您的示例。由于您的操作与我基本相同,因此差异可能在于调用的进程或底层操作系统(在我的情况下为 MacOsX)甚至 Java 版本。我会看看我能找到什么,谢谢你的回复!
  • @roesslerj,您仍然应该先检查标准错误。可能是一个愚蠢的错误,会阻止正在执行的命令的正常操作。或者它可能正试图将某种警告写入 stderr 并被阻止,因为 stderr 没有缓冲,而另一端(您的进程)没有读取任何内容。
  • 感谢您提供这段代码。事实证明,您的代码也适用于我......而且我在 StreamGobbler 类的省略代码中犯了一个愚蠢的错误(根据你的建议,我将其用于 stdout 和 stderr ......只是一个小错误备注:out.write(System.getProperty("line.separator")); 的结果与调用out.newLine(); 的结果相同。
  • @roesslerj,当然可以。我完全忘记了 newLine()。我认为那段代码有些愚蠢...
【解决方案2】:

out.write((char) 13) 呢?请参阅此Wikipedia 文章。我没有足够的代码来为你测试。

【讨论】:

  • Java中的回车字符用'\r'表示,所以我已经尝试过了(见正文),但仍然感谢输入。
【解决方案3】:

您可能还想尝试查看此 API

http://download.oracle.com/javase/6/docs/api/java/io/Console.html

根据我的经验,除了从 Process API 运行一个进程之外,我从未尝试过做任何其他事情。您似乎想输入多个命令,我认为此 API 可能会让您这样做。

编辑:找到了一个教程来帮助你进一步。 http://download.oracle.com/javase/tutorial/essential/io/cl.html

希望这会有所帮助,

【讨论】:

  • 我可能弄错了,但是当您自己编写交互式控制台时,此 API 似乎更像您想要的。但这不是我想做的;我必须以外部进程的形式与这样的控制台进行交互。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-24
  • 1970-01-01
  • 2010-11-16
  • 1970-01-01
  • 2014-12-27
相关资源
最近更新 更多