Java执行cmd命令

前言

Java应用程序主要是通过Runtime和Process两个类来执行cmd命令。
Runtime.exec方法创建本机进程并返回Process子类的实例,该实例可用于控制进程并获取有关它的信息。
Process类提供了从进程执行输入,执行输出到进程,等待进程完成,检查进程的退出状态以及销毁(杀死)进程的方法。
具体有哪些方法请查看相关文档:https://docs.oracle.com/javase/8/docs/api/

Runtime类

Runtime类位于java.lang包下,继承Object类。
每个Java应用程序都有且只有一个Runtime类实例,它允许应用程序与运行应用程序的环境进行交互。 可以从getRuntime方法获取当前运行时。
从类的实现方式来看,明显是个单例模式,只能通过getRuntime()来获取当前类的实例。

/**
 * Every Java application has a single instance of class
 * <code>Runtime</code> that allows the application to interface with
 * the environment in which the application is running. The current
 * runtime can be obtained from the <code>getRuntime</code> method.
 * <p>
 * An application cannot create its own instance of this class.
 */
 public class Runtime {
    private static Runtime currentRuntime = new Runtime();

    /**
     * Returns the runtime object associated with the current Java application.
     * Most of the methods of class <code>Runtime</code> are instance
     * methods and must be invoked with respect to the current runtime object.
     *
     * @return  the <code>Runtime</code> object associated with the current
     *          Java application.
     */
    public static Runtime getRuntime() {
        return currentRuntime;
    }

    /** Don't let anyone else instantiate this class */
    private Runtime() {}

    ......
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

public static Runtime getRuntime()方法

返回与当前Java应用程序关联的运行时对象。 类Runtime的大多数方法都是实例方法,必须根据当前运行时对象进行调用。

public Process exec(String command) throws IOException方法

在单独的进程中执行指定的字符串命令。
这是一种方便的方法。 调用exec(command)形式的行为与调用exec(command,null,null)完全相同。

public Process exec(String[] cmdarray, String[] envp, File dir) throws IOException方法

在具有指定环境和工作目录的单独进程中执行指定的命令和参数。

给定一个字符串数组cmdarray,表示命令行的标记,以及一个字符串envp数组,表示“环境变量”设置,此方法创建一个执行指定命令的新进程。
此方法会检查cmdarray是否为有效的操作系统命令。命令是否有效取决于程序运行所在的操作系统,但至少该命令必须是非空字符串的非空列表。
如果envp为null,则子进程将继承当前进程的环境设置。
在某些操作系统上启动进程可能需要一组最小的系统相关环境变量。因此,子进程可以继承除指定环境中的其他环境变量设置。
ProcessBuilder.start()现在是使用已修改环境启动进程的首选方法。
新子进程的工作目录由dir指定。如果dir为null,则子进程将继承当前进程的当前工作目录。
如果存在安全管理器,则调用其checkExec方法,并将数组cmdarray的第一个组件作为其参数。这可能会导致抛出SecurityException。
启动操作系统进程高度依赖于程序运行所在的操作系统。在许多可能出现如下错误:

找不到操作系统程序文件。
访问程序文件被拒绝。
工作目录不存在。
在这种情况下,程序将会抛出异常。异常的确切性质取决于操作系统,但它始终是IOException的子类。

Process类

Process类同样位于java.lang包下,继承Object类。
ProcessBuilder.start()和Runtime.exec方法创建本机进程并返回Process子类的实例,该实例可用于控制进程并获取有关它的信息。 Process类提供了从进程执行输入,执行输出到进程,等待进程完成,检查进程的退出状态以及销毁(杀死)进程的方法。
创建进程的方法可能不适用于某些本机平台上的特殊进程,例如本机窗口进程,守护程序进程,Microsoft Windows上的Win16 / DOS进程或shell脚本。
默认情况下,创建的子进程没有自己的终端或控制台。它的所有标准I/O(即stdin,stdout,stderr)操作将被重定向到父进程,在那里可以通过使用方法getOutputStream(),getInputStream()和getErrorStream()获得的流来访问它们。父进程使用这些流向子进程提供输入并从子进程获取输出。由于某些本机平台仅为标准输入和输出流提供有限的缓冲区大小,因此无法及时写入输入流或读取子进程的输出流可能导致子进程阻塞甚至死锁。
如果需要,还可以使用ProcessBuilder类的方法重定向子进程I/O.
当没有对Process对象的更多引用时,子进程不会被终止,而是子进程继续异步执行。
不要求Process对象表示的进程相对于拥有Process对象的Java进程异步或并发执行。

public boolean waitFor(long timeout, TimeUnit unit) throws InterruptedException方法

如果需要,使当前线程等待,直到此Process对象表示的子进程终止,或者指定的等待时间。
如果子进程已经终止,则此方法立即返回值true。 如果进程尚未终止且超时值小于或等于零,则此方法立即返回值false。
此方法的默认实现轮询exitValue的值以检查进程是否已终止。 强烈建议采用更高效的实现方式来覆盖此类的方法。

具体使用

public class cmdTask implements Runnable {
    private String command;

    public cmdTask (String command) {
        this.command = comand;
     }

    @Override
    public void run() {
        Process process = null;
        int exitVal = 0;
        try {
            process = Runtime.getRuntime().exec(command);
            // Runtime.exec()创建的子进程公用父进程的流,不同平台上,父进程的stream buffer可能被打满导致子进程阻塞,从而永远无法返回。
            //针对这种情况,我们只需要将子进程的stream重定向出来即可。
            new RedirCmdStreamThread(process.getInputStream(), "INFO").start();
            new RedirCmdStreamThread(process.getErrorStream(),"ERR").start();

            exitVal = process.waitFor();
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
        
        if (exitVal != 0){
            throw new RuntimeException("cmd任务执行失败");
        }
    }

    class RedirCmdStreamThread extends Thread {
        InputStream is;
        String printType;

        RedirCmdStreamThread(InputStream is, String printType) {
            this.is = is;
            this.printType = printType;
        }

        public void run() {
            try {
                InputStreamReader isr = new InputStreamReader(is);
                BufferedReader br = new BufferedReader(isr);
                String line = null;
                while ( (line = br.readLine()) != null) {
                    System.out.println(printType + ">" + line);
                }

            } catch (IOException ioe)
            {
                ioe.printStackTrace();
            }
        }
    }
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Code Writers

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值