• Java 执行系统命令


    在Java中执行系统命令,主要是使用ProcessBuilder和Runtime.getRuntime().exec()。而在这里主要是介绍两种方法的使用。
    使用情景是在linux系统中,使用mencoder来进行视频转码。将视频转为flv格式,因为转为flv格式命令较为简单,如要转为MP4格式,可以看官方文档介绍

    一.使用Runtime

    ##上传之后的视频文件名为test.tmpmedia
    String command = "mencoder test.tmpmedia -o test.flv -ofps 25 -of lavf -oac mp3lame -srate 22050 -ovc lavc -lavcopts "
                    + "vcodec=flv:keyint=59:vbitrate=6000:mbd=2:trell:v4mv:o=mpv_flagg=cbp_rd:last_pred=3 -vf harddup,scale=480:256";
    
    Process p = Runtime.getRuntime().exec(command);
    
    ##读取命令的输出信息
    InputStream is = p.getInputStream();
    BufferedReader reader = new BufferedReader(new InputStreamReader(is));
    p.waitFor();
    if (p.exitValue() != 0) {
        //说明命令执行失败
        //可以进入到错误处理步骤中
    }
    
    ##打印输出信息
    String s = null;
    while ((s = reader.readLine()) != null) {
        System.out.println(s);
    }
    

    其中waitFor()方法会阻塞当前进程,直到命令执行结束。而exitValue不会阻塞进程,但是调用exitValue的时候,如果命令没有执行完成就会报错,感觉这样设计挺奇怪的。
    所以,想要获取到命令是否执行成功,就搭配waitForexitValue

    使用Runtime执行命令感觉是比较方便的,直接可以将命令写入exec()中。如果仅仅是这样写的话,转码是会一直卡死在那里的。而你将命令直接放到终端中执行,又不会出现问题。
    原因就在转码时候,会输出大量的信息(标准输出和标准错误),如果不清理java的缓存区,就会导致缓存区满而命令无法继续执行的情况。
    那么解决办法肯定就是清理缓存区,而使用Runtime清理的话,你至少得再开另外一个线程,才能同时getInputStreamgetErrorStream,这样并不是我喜欢的,所以便采用了ProcessBuilder

    二.使用ProcessBuilder

    #将命令分解为List存储
    String[] commandSplit = command.split(" ");
    List<String> lcommand = new ArrayList<String>();
    for (int i = 0; i < commandSplit.length; i++) {
    	lcommand.add(commandSplit[i]);
    }
    
    ProcessBuilder processBuilder = new ProcessBuilder(lcommand);
    processBuilder.redirectErrorStream(true);
    Process p = processBuilder.start();
    InputStream is = p.getInputStream();
    BufferedReader bs = new BufferedReader(new InputStreamReader(is));
    
    p.waitFor();
    if (p.exitValue() != 0) {
        //说明命令执行失败
        //可以进入到错误处理步骤中
    }
    String line = null;
    while ((line = bs.readLine()) != null) {
    	System.out.println(line);
    	resultLog += line;
    }
    

    ProcessBuilder可以使用redirectErrorStream将标准输出和标准错误流合并,然后使用getInputStream获取到流,放入BufferedReader中打印出来,便可解决缓存区满的问题
    唯一感觉不太方便就是命令执行已List<String>或者String []的形式传入。

    上面的两种方法都是以阻塞的方式执行命令的,要想在后台执行命令,并且命令执行成功后通知,失败后记录日志,那就只能在主线程中开一个线程,专门用来转码。可以参考下一篇文章《
    Spring中多线程转码,bean的注入问题》

  • 相关阅读:
    C++ 把输出结果写入文件/从文件中读取数据
    转载:C++之高精度算法
    借助bool判断使冒泡排序效率提高
    启程
    2017总结,2018的路
    mysql 分组排序
    2021年VS2019最新有效的调试ASP.NET Core源码
    神级Java程序员 开车教你基础开发,最简单 微型Java Web框架
    手把手教你 基础 整合最优雅SSM框架:SpringMVC + Spring
    学习Java绝对要懂的,Java编程中最常用的几种排序算法!
  • 原文地址:https://www.cnblogs.com/bencakes/p/6139477.html
Copyright © 2020-2023  润新知