如何通过ProcessBuilder向已启动的进程输入数据?
解决ProcessBuilder向持续运行的闭源程序输入数据的问题
你的代码核心问题在于PrintWriter的缓冲区没有刷新,写入的数据还停留在JVM的输出缓冲区里,没有真正发送给子进程。另外还要注意处理子进程的标准输出和错误输出,避免因为流阻塞导致程序挂起。下面是具体的修正方案:
1. 强制刷新输出缓冲区
PrintWriter默认带缓冲,调用write后数据不会立即发送,必须手动刷新或开启自动刷新:
ProcessBuilder pb = new ProcessBuilder("/path/to/executable"); Process p = pb.start(); // 方式1:构造时开启自动刷新(第二个参数设为true) PrintWriter pw = new PrintWriter(p.getOutputStream(), true); pw.println("Hey"); // println会自动生成换行符并触发刷新 // 方式2:手动调用flush // PrintWriter pw = new PrintWriter(p.getOutputStream()); // pw.write("Hey\n"); // pw.flush(); // 必须调用,否则数据不会传递给子进程 String result = read(p); System.out.println("Out: " + result); p.destroy();
2. 匹配子进程的输入格式要求
部分程序要求输入以\r\n(Windows风格换行)结尾,而非\n。可以尝试用pw.println("Hey")(自动适配系统换行符),或者直接写入"Hey\r\n"测试。
3. 处理错误流避免阻塞
子进程若有错误输出但未被读取,会导致输出缓冲区满而挂起。建议单独开线程读取错误流:
// 启动线程读取错误流,防止主进程阻塞 new Thread(() -> { try (BufferedReader errReader = new BufferedReader(new InputStreamReader(p.getErrorStream()))) { String line; while ((line = errReader.readLine()) != null) { System.err.println("子进程错误输出: " + line); } } catch (IOException e) { e.printStackTrace(); } }).start();
4. 检查read方法的实现
如果read(p)方法的逻辑有问题(比如只读取部分输出),也会导致拿不到结果。建议用BufferedReader完整读取:
private static String read(Process p) throws IOException { StringBuilder sb = new StringBuilder(); try (BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()))) { String line; // 根据子进程的输出逻辑调整,比如读取一行或持续读取直到流结束 if ((line = reader.readLine()) != null) { sb.append(line); } } return sb.toString(); }
5. 可选:合并错误流到标准输出
通过ProcessBuilder将错误流合并到标准输出,方便统一处理:
pb.redirectErrorStream(true);
内容的提问来源于stack exchange,提问作者Petrov Crowford
相关产品推荐
相关产品推荐

