You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 19:37:31