Java程序化启动Windows命令行程序并交互:输入密码读取输出问题
解决Java启动需交互输入密码的Windows程序并捕获输出的问题
你的问题核心出在重定向设置上:当你使用Redirect.INHERIT时,已经把目标程序的输入、输出、错误流直接绑定到了Java进程的控制台,这意味着process.getInputStream()根本拿不到任何数据——所有输出都直接打印到你运行Java程序的控制台了,同时输入也直接从控制台读取,完全绕开了Java程序的控制。
要实现程序化输入密码并捕获输出,你需要让Java自己接管目标程序的输入输出流,而不是继承控制台。下面是修改后的完整代码,我会逐点解释关键改动:
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.nio.charset.StandardCharsets; public class RunCommand { public static void main(String[] args) throws Exception { new RunCommand().go(); } void go() throws Exception { // 初始化ProcessBuilder,不设置INHERIT重定向(默认用管道流) ProcessBuilder pb = new ProcessBuilder("executable.exe"); // 把错误流合并到输出流,只需要处理一个流即可 pb.redirectErrorStream(true); Process process = pb.start(); // 启动单独线程读取目标程序的输出 Thread outputReader = new Thread(() -> { try (BufferedReader reader = new BufferedReader( new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8))) { String line; // 逐行读取输出,比逐个字节读更高效且易处理 while ((line = reader.readLine()) != null) { System.out.println("[程序输出] " + line); } } catch (IOException e) { e.printStackTrace(); } }); outputReader.start(); // 向目标程序输入密码 try (OutputStreamWriter writer = new OutputStreamWriter( process.getOutputStream(), StandardCharsets.UTF_8)) { // 写入密码后要加Windows换行符\r\n(部分程序可能只需要\n,可根据实际调整) writer.write("你的目标密码\r\n"); // 强制刷新缓冲区,确保密码被立即发送到目标程序 writer.flush(); } // 等待目标程序执行完成,替代你的无限循环 int exitCode = process.waitFor(); System.out.println("程序执行结束,退出码:" + exitCode); // 等待输出读取线程处理完剩余内容 outputReader.join(); } }
关键改动说明:
- 移除INHERIT重定向:默认情况下ProcessBuilder会为进程创建管道流,Java可以通过
getInputStream()、getOutputStream()直接操控这些流,这是实现程序间交互的基础。 - 用BufferedReader高效读取输出:逐个字节读取不仅低效,还容易出现字符编码问题,用BufferedReader逐行读取更符合命令行程序的输出习惯。
- 正确写入密码:必须通过
OutputStreamWriter向目标程序的输入流写入密码,并且要添加换行符——命令行程序需要接收到回车信号才会处理输入的密码。另外要注意编码,Windows程序通常用GBK或UTF-8,可根据实际情况调整StandardCharsets。 - 等待进程执行完成:用
process.waitFor()替代你的无限循环,既保证目标程序能正常执行完毕,也能确保输出线程读完所有内容后再结束。
额外注意事项:
- 如果目标程序的密码输入没有回显(比如输入时看不到星号),这是正常的,不影响Java程序的输入传递。
- 如果遇到输出乱码问题,可以尝试把
StandardCharsets.UTF_8换成StandardCharsets.ISO_8859_1或"GBK"。 - 可以添加超时逻辑避免目标程序挂起:比如用
process.waitFor(10, TimeUnit.SECONDS),超时后调用process.destroyForcibly()终止进程。
内容的提问来源于stack exchange,提问作者Hmmmmm
相关产品推荐
相关产品推荐

