前言:虽然没什么空,但是也要硬着头皮更新一下最近遇到的问题。
Java项目中需要调用到ffmpeg命令,得知Java的Process类可以使用。
常规的Process类使用网上有很多,贴一个最经典的例子。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
public class ExecShell {
public static void main(String args[]) {
Process process = null;
List processList = new ArrayList();
try {
process = Runtime.getRuntime().exec("ps -aux");
BufferedReader input = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = "";
while ((line = input.readLine()) != null) {
processList.add(line);
}
input.close();
try {
process.waitFor();
} catch (Throwable e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
for (String line : processList) {
System.out.println(line);
}
}
}
这里Runtime类是单例,从该类调用exec(String)方法可以获得Process对象。Process对象有三个流对象,对应三个管道:标准输入流,标准输出流和错误流。标准输入流和错误流其实是Process类的输出,标准输出流则是Java代码对Process对象的输入。
一般来说是相安无事的,不过当你调用长时间工作的命令时,该命令的输入流里将有大量数据写进缓冲区,若你不取出来,命令将不再执行,而是阻塞,等待你的取出。这是代码就无法继续运行下去了。
当我在jdk7和tomcat6下把三个流都关闭时,shell命令是可以执行的。
process.getErrorStream().close();
process.getInputStream().close();
process.getOutputStream().close();
但是,当我部署到jdk8和tomcat7时,以上的代码使得shell命令不执行,所以我只能一直把输入流的数据取出来。这次,我使用ProcessBuilder类获得Process对象,把标准输入流和错误流合并,并且一直往输入流取出数据。于是长时间运行的shell命令得以运行。
@Override
public String call(String shellString){
Process process = null;
try {
ProcessBuilder pBuilder = new ProcessBuilder(shellString.split(" "));
pBuilder.redirectErrorStream(true);
process = pBuilder.start();
process.getOutputStream().close();
BufferedReader input = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = "";
while ((line = input.readLine()) != null) {
//System.out.println(line);
}
input.close();
System.out.println(shellString);
try{
process.waitFor();
}catch(Throwable e){
e.printStackTrace();
}
process.destroy();
} catch (IOException e) {
e.printStackTrace();
}
return " ";
}
最后建议,输入流的数据还是取出来吧,close()的话会出问题的说。