使用ProcessBuilder执行本地程序的注意事项

错误代码

    public static void main(String[] args) throws IOException, InterruptedException {
        ProcessBuilder processBuilder = new ProcessBuilder("java","-version");
        Process process = processBuilder.start();
        InputStream inputStream = process.getInputStream();
        xxx(inputStream);
    }


    private static void xxx(InputStream inputStream) throws IOException {
        BufferedReader input = new BufferedReader(new InputStreamReader(inputStream));
        String ss=null;
        while ((ss=input.readLine())!=null){
            System.out.println(ss);
        }
    }

使用ProcessBuilder类带参执行命令容易出现的两个坑

    1、执行后没有任何反映

        原因为通过ProcessBuilder运行的参数还没有执行完毕程序就退出了。

        通过if(process.isAlive()){process.waitFor();}可以规避此问题,但是需要注意waitFor时程序时阻塞的,如果是持续运行的web项目可以通过开启子线程来执行ProcessBuilder

    2、执行后没有任何输出

        最恶心的地方,除了getInputStream外还有一个getErrorStream也可以获取数据,而且一般执行的程序数据都会输出在getErrorStream中,所以getInputStream无法获取到数据

处理后的代码

    public static void main(String[] args) throws IOException, InterruptedException {
        ProcessBuilder processBuilder = new ProcessBuilder("java","-version");
        processBuilder.redirectErrorStream(true);//将错误流中的数据合并到输入流
        Process process = processBuilder.start();
        if(process.isAlive()){
            process.waitFor();
        }
//        InputStream errorStream = process.getErrorStream();
        InputStream inputStream = process.getInputStream();
//        xxx(errorStream);
        xxx(inputStream);
    }


    private static void xxx(InputStream inputStream) throws IOException {
        BufferedReader input = new BufferedReader(new InputStreamReader(inputStream));
        String ss=null;
        while ((ss=input.readLine())!=null){
            System.out.println(ss);
        }
    }

后续发现新的问题,当某个软件会持续向流中写数据,这时流中数据没有被读取完毕(流中存在数据【测试发现流中存在数据并不是一定会阻塞】),会导致waitFor一直陷入阻塞

上述问题处理后的代码(正确使用ProcessBuilder的代码)

    public static void main(String[] args) throws IOException, InterruptedException {
        ProcessBuilder processBuilder = new ProcessBuilder("java","-version");
        processBuilder.redirectErrorStream(true);
        Process process = processBuilder.start();
//        通过标准输入流来拿到正常和错误的信息
        InputStream inputStream = process.getInputStream();
        BufferedReader input = new BufferedReader(new InputStreamReader(inputStream));
        String ss=null;
        while ((ss=input.readLine())!=null){
            System.out.println(ss);
        }
        process.waitFor();
    }

复现错误:

1、某个软件持续向流中写数据时,如果流中数据未被读取完毕waitFor一直陷入等待

    public static void main(String[] args) throws IOException, InterruptedException {
        ProcessBuilder processBuilder = new ProcessBuilder();
        List<String> meta = new ArrayList<String>();
        meta.add("ffmpeg");
        meta.add("-i");
        meta.add("C:/Users/Lenovo/Desktop/20200801134820261.mp3");
        meta.add("-af");
        meta.add("silencedetect=n=-1dB:d=0.5");
        meta.add("-f");
        meta.add("null");
        meta.add("-");
        processBuilder.command(meta);
        processBuilder.redirectErrorStream(true);
        Process process = processBuilder.start();
        InputStream inputStream = process.getInputStream();
//        BufferedReader input = new BufferedReader(new InputStreamReader(inputStream));
//        String ss=null;
//        while ((ss=input.readLine())!=null){
//            System.out.println(ss);
//        }
        process.waitFor();
        System.out.println("一直阻塞无法执行到这一步");
    }

2、通过下面代码证明上面的观点:当将流中数据读取完毕后waitFor不会阻塞,可执行下一步

public static void main(String[] args) throws IOException, InterruptedException {
    ProcessBuilder processBuilder = new ProcessBuilder();
    List<String> meta = new ArrayList<String>();
    meta.add("ffmpeg");
    meta.add("-i");
    meta.add("C:/Users/Lenovo/Desktop/20200801134820261.mp3");
    meta.add("-af");
    meta.add("silencedetect=n=-1dB:d=0.5");
    meta.add("-f");
    meta.add("null");
    meta.add("-");
    processBuilder.command(meta);
    processBuilder.redirectErrorStream(true);
    Process process = processBuilder.start();
    InputStream inputStream = process.getInputStream();
    BufferedReader input = new BufferedReader(new InputStreamReader(inputStream));
    String ss=null;
    while ((ss=input.readLine())!=null){
        System.out.println(ss);
    }
    process.waitFor();
    System.out.println("正常输出");
}
3、与上面观点产生矛盾的代码:下面代码中的流中仍然存在数据,但是waitFor并没有陷入阻塞,推测原因可能是由于ipconfig与ffmpeg不同,不存在 持续向流中写数据情况,因此waitFor可以正常结束阻塞
    public static void main(String[] args) throws IOException, InterruptedException {
        ProcessBuilder processBuilder = new ProcessBuilder();
        List<String> meta = new ArrayList<String>();
        meta.add("ipconfig");
        processBuilder.command(meta);
        processBuilder.redirectErrorStream(true);
        Process process = processBuilder.start();
        InputStream inputStream = process.getInputStream();
//        BufferedReader input = new BufferedReader(new InputStreamReader(inputStream));
//        String ss=null;
//        while ((ss=input.readLine())!=null){
//            System.out.println(ss);
//        }
        process.waitFor();
        System.out.println("正常输出");
    }

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值