使用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的分布式锁中也有相同的角色。

参考

程序员的福音 - Apache Commons Exec

posted @   strongmore  阅读(68)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 什么是nginx的强缓存和协商缓存
· 一文读懂知识蒸馏
· Manus爆火,是硬核还是营销?
历史上的今天:
2022-03-16 浏览器的DNS解析过程分析
2021-03-16 图的基本表示-邻接矩阵和邻接表
点击右上角即可分享
微信分享提示