使用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的分散式鎖中也有相同的角色。
參考
程式設計師的福音 - Apache Commons Exec