从JSF CDI Bean调用外部可执行程序输出不完整,独立程序正常
解决Payara Server中调用外部程序输出不全的问题
问题出在外部进程的标准输出与标准错误流未同时处理。当外部程序向标准错误输出内容时,错误流的缓冲区会被填满,导致进程阻塞,无法继续向标准输出写入数据,最终只输出首尾行。独立Java程序通常在控制台环境下,系统会自动处理两个流的输出,所以不会出现这个问题。
解决方法1:合并标准错误流到标准输出
通过ProcessBuilder的redirectErrorStream(true)方法,将错误流合并到标准输出,这样只需要读取一个流即可获取所有输出:
@Named @ViewScoped public class TestBean implements Serializable { public void compute() throws IOException, InterruptedException { String executable = "./xyz.exe"; String parameter1 = "90.0"; String parameter2 = "13.0"; File executeDirectory = new File("/path/to/executable"); ProcessBuilder pb = new ProcessBuilder(executable, parameter1, parameter2); pb.directory(executeDirectory); // 合并错误流到标准输出 pb.redirectErrorStream(true); Process p = pb.start(); // 读取合并后的输出流 try (BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()))) { String line; while ((line = reader.readLine()) != null) { System.out.println(line); // 后续可解析并存储输出用于页面展示 } } // 等待进程执行完成,确保所有输出都被读取 int exitCode = p.waitFor(); System.out.println("外部程序退出码:" + exitCode); } }
解决方法2:用独立线程分别处理两个流
如果需要区分标准输出和错误输出,可启动两个线程分别读取两个流,避免互相阻塞:
@Named @ViewScoped public class TestBean implements Serializable { public void compute() throws IOException, InterruptedException { String executable = "./xyz.exe"; String parameter1 = "90.0"; String parameter2 = "13.0"; File executeDirectory = new File("/path/to/executable"); ProcessBuilder pb = new ProcessBuilder(executable, parameter1, parameter2); pb.directory(executeDirectory); Process p = pb.start(); // 线程处理标准输出 Thread outputThread = new Thread(() -> { try (BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()))) { String line; while ((line = reader.readLine()) != null) { System.out.println("标准输出:" + line); // 处理标准输出内容 } } catch (IOException e) { e.printStackTrace(); } }); // 线程处理标准错误 Thread errorThread = new Thread(() -> { try (BufferedReader reader = new BufferedReader(new InputStreamReader(p.getErrorStream()))) { String line; while ((line = reader.readLine()) != null) { System.out.println("错误输出:" + line); // 处理错误输出内容 } } catch (IOException e) { e.printStackTrace(); } }); // 启动两个线程 outputThread.start(); errorThread.start(); // 等待线程和进程完成 outputThread.join(); errorThread.join(); int exitCode = p.waitFor(); System.out.println("外部程序退出码:" + exitCode); } }
额外注意事项
- 务必使用
try-with-resources确保流资源被正确关闭,避免内存泄漏。 - 调用
waitFor()等待进程执行完毕,保证所有输出都被读取完成。 - 如果外部程序输出量较大,建议使用
BufferedReader提升读取效率,避免频繁IO操作。
内容的提问来源于stack exchange,提问作者Sachin Narang
相关产品推荐
相关产品推荐

