使用java创建新的进程
使用jdk内置的工具
import org.apache.commons.io.IOUtils;
import java.nio.charset.Charset;
public class TestProcess {
public static void main(String[] args) throws Exception {
testExec();
}
private static void testExec() throws Exception {
String commandPath = "/bin/ls";
String param = "/Users/xxx/testjars";
String fullCommand = new StringBuilder()
.append(commandPath)
.append(" ")
.append(param)
.toString();
Process process = Runtime.getRuntime().exec(fullCommand);
int exitCode = process.waitFor();
// 状态码0表示执行成功
if (exitCode == 0) {
String result = IOUtils.toString(process.getInputStream(), Charset.forName("GBK"));
System.out.println(result);
} else {
String errMsg = IOUtils.toString(process.getErrorStream(), Charset.forName("GBK"));
System.out.println(errMsg);
}
}
}
Runtime 的 exec() 方法内部会将完整命令使用 空格或者换行 分割为多个,第一个当作执行命令,后面的当作执行参数。内部使用 ProcessBuilder 来创建 Process。
import org.apache.commons.io.IOUtils;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.List;
public class TestProcess2 {
public static void main(String[] args) throws Exception {
testExec();
}
private static void testExec() throws IOException, InterruptedException {
String commandPath = "/bin/ls";
String param = "/Users/xxx/testjars";
List<String> commands = Arrays.asList(commandPath, param);
Process process = new ProcessBuilder().command(commands).start();
int exitCode = process.waitFor();
// 状态码0表示执行成功
if (exitCode == 0) {
String result = IOUtils.toString(process.getInputStream(), Charset.forName("GBK"));
System.out.println(result);
} else {
String errMsg = IOUtils.toString(process.getErrorStream(), Charset.forName("GBK"));
System.out.println(errMsg);
}
}
}
和上面类似,直接使用 ProcessBuilder 来创建 Process。注意,这个时候,command() 方法不能直接传一个完整命令,如下所示
private static void testExec2() throws IOException, InterruptedException {
String commandPath = "/bin/ls";
String param = "/Users/xxx/testjars";
String fullCommand = new StringBuilder()
.append(commandPath)
.append(" ")
.append(param)
.toString();
List<String> commands = Arrays.asList(fullCommand);
Process process = new ProcessBuilder().command(commands).start();
int exitCode = process.waitFor();
...
}
这种情况会报错
Exception in thread "main" java.io.IOException: Cannot run program "/bin/ls /Users/xxx/testjars": error=2, No such file or directory
at java.lang.ProcessBuilder.start(ProcessBuilder.java:1048)
at com.imooc.TestProcess2.testExec2(TestProcess2.java:41)
at com.imooc.TestProcess2.main(TestProcess2.java:12)
Caused by: java.io.IOException: error=2, No such file or directory
at java.lang.UNIXProcess.forkAndExec(Native Method)
at java.lang.UNIXProcess.<init>(UNIXProcess.java:247)
at java.lang.ProcessImpl.start(ProcessImpl.java:134)
at java.lang.ProcessBuilder.start(ProcessBuilder.java:1029)
... 2 more
它是把 完整命令当作 执行命令了,就会报找不到这个命令(/bin/ls /Users/xxx/testjars)。
使用apache的commons-exec工具
引入依赖
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-exec</artifactId>
<version>1.3</version>
</dependency>
代码如下
import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.PumpStreamHandler;
import java.io.ByteArrayOutputStream;
public class TestCommonsExec {
public static void main(String[] args) throws Exception {
testExec();
}
private static void testExec() throws Exception {
String commandPath = "/bin/ls";
String param = "/Users/zzshi/szz_files/testjars";
String fullCommand = new StringBuilder()
.append(commandPath)
.append(" ")
.append(param)
.toString();
//接收正常结果流
ByteArrayOutputStream susStream = new ByteArrayOutputStream();
//接收异常结果流
ByteArrayOutputStream errStream = new ByteArrayOutputStream();
CommandLine commandLine = CommandLine.parse(fullCommand);
DefaultExecutor exec = new DefaultExecutor();
PumpStreamHandler streamHandler = new PumpStreamHandler(susStream, errStream);
exec.setStreamHandler(streamHandler);
int exitCode = exec.execute(commandLine);
// 状态码0表示执行成功
if (exitCode == 0) {
String result = susStream.toString("GBK");
System.out.println(result);
} else {
String errMsg = errStream.toString("GBK");
System.out.println(errMsg);
}
}
}
使用 commons-exec 更加的方便,且支持异步、超时取消等更多功能,使用 ExecuteWatchdog 来实现超时取消(内部创建一个线程一直监听)。Watchdog也就是看门狗,Redission的分布式锁中也有相同的角色。