【问题标题】:Reading output from never ending CMD process in Java从 Java 中永无止境的 CMD 进程读取输出
【发布时间】:2020-10-22 19:32:18
【问题描述】:

我想要达到的目标:

我有一个启动 ngrok 的 JAVA 代码(ngrok 用于将您的本地端口公开给网络,以便其他人可以访问它。更多信息here)进程。现在使用Runtime.getRuntime() 生成新的 ngrok 进程后,我想读取它的输出。

问题:

当我尝试使用getInputStream()getErrorStream()InputStream 读取数据时,我的程序卡在了那里。所以我无法读取进程的输出。

代码:

Process ngrokProcess = Runtime.getRuntime().exec(" cmd /k start cmd /k \" ngrok http 8080 \" ");
    
String collect = Stream.of(ngrokProcess.getInputStream(), ngrokProcess.getErrorStream()).parallel().map((InputStream is) -> {
                StringBuilder output = new StringBuilder();
                try (BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
                    String line;
                    while ((line = br.readLine()) != null) {
                        output.append(line);
                        output.append("\n");
                    }
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
                return output;
            }).collect(Collectors.joining());

我在这里做错了什么?或者有没有其他方法可以实现?

我不能等待进程完成,因为除非被强制终止,否则它永远不会结束。另外,我不能使用ProcessBuilder,因为用户看不到命令​​提示符(我在这里可能错了,需要调整一些东西才能看到。如果可能的话,请告诉我)。

如果需要更多信息,请告诉我。

提前致谢:)

【问题讨论】:

    标签: java cmd process io processbuilder


    【解决方案1】:

    您应该检查/修改一些事情。

    Runtime.getRuntime() 使用ProcessBuilder,最好直接使用ProcessBuilder,因为您可以更好地控制启动 - 尤其是文件重定向或 STDERR 到 STDOUT 的切换。

    你执行的命令是CMD,它调用CMD作为调用ngrok的新进程。由于子进程,stdout/stderr 流不会用于 ngrok。

    所以尝试通过在 CMD.EXE 中解析 ngrok 的路径来绕过不必要的 CMD:

    where ngrok
    

    将调用定义为 String[]

    String[] cmd = new String[] {"/path/to/ngrok", "http", "8080"  }
    Process ngrokProcess = Runtime.getRuntime().exec(cmd);
    

    您的命令现在可能会启动,但您可能遇到的另一个问题是,如果您没有足够快地消耗输出,它将阻塞进程。您可以将输出重定向到文件或添加线程来使用流。

    我刚刚在另一个 SO 问题中发布了一个 Launch 类,它展示了如何使用文件重定向执行命令。见Launch.exec(cmd)

    但是,运行后台线程来消耗 STDOUT/ERR 对于长时间运行的任务来说更好,因为这些后台线程可以在运行时扫描输出,而文件重定向对于短时间运行和后处理更容易过程结束。如果您的应用程序需要继续,您应该让后台线程执行waitFor()

    【讨论】:

    • 嗨@DuncG,感谢您的帮助,但我使用的是 Runtime 而不是 ProcessBuilder,因为我希望用户在前台看到 cmd 终端,而我无法在 ProcessBuilder 中看到。有什么办法吗?
    • 另一种解决方案可能是运行conhost.exe 以启动新窗口并使用process.getOutStream() 向其发送命令。在这里查看答案:[stackoverflow.com/questions/63244536/…
    • 好的@DuncG,我去看看。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多