如何使用 Java 中执行 Windows 的 CMD 命令

  在 CMD 中执行 BAT 脚本对用户不友好,而且有安全隐患,因此笔者编写了一些可以在 Java 中执行 Windows 的 CMD 命令的 API。

核心代码

  • 执行单条命令
package org.wangpai.demo;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.stream.Collectors;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.experimental.Accessors;

/**
 * @since 2021-12-21
 */
@Accessors(chain = true)
public class WinCmd {
    private Charset cmdCharset;

    @Getter(AccessLevel.PROTECTED)
    private Process process;

    private String originalCommandMsg;

    private String output;

    private int exitValue;

    private WinCmd() {
        super();
    }

    public static WinCmd getInstance() {
        return new WinCmd();
    }

    /**
     * 如果调用本方法时,本方法会阻塞调用线程,直到命令执行结束
     *
     * @since 2021-12-21
     */
    public int getExitValue() throws Exception {
        if (this.process == null) {
            throw new Exception("需要先执行命令后才能获取退出码");
        }

        this.exitValue = process.waitFor();
        return this.exitValue;
    }

    public String getOutput() throws Exception {
        if (this.process == null) {
            throw new Exception("需要先执行命令后才能获取输出");
        }
        if (this.output != null) {
            return this.output;
        }

        var inputStream = process.getInputStream();
        // 获取操作系统(命令行)的字符集
        this.cmdCharset = Charset.forName((String) System.getProperties().get("sun.jnu.encoding"));
        // 将输出按行分成多个字符串。这原本不是想要的操作,但这没有办法
        var lines = new BufferedReader(new InputStreamReader(
                inputStream, this.cmdCharset)).lines();
        this.output = lines.collect(Collectors.joining(System.lineSeparator()));
        // 将每行字符串以换行符拼接,还原出原始信息
        return this.output;
    }

    public String getCommand() throws Exception {
        if (this.originalCommandMsg == null) {
            throw new Exception("还没有输入命令");
        }

        return this.originalCommandMsg;
    }

    public WinCmd execute(String command) throws Exception {
        return this.exec(command);
    }

    private WinCmd exec(String originalCommand) throws IOException {
        this.output = null;
        this.originalCommandMsg = originalCommand;
        this.process = Runtime.getRuntime().exec(this.originalCommandMsg);
        return this;
    }
}

  • 执行多条命令
package org.wangpai.demo;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @since 2021-12-21
 */
public class WinBat {
    private int commandNum;

    private Charset cmdCharset;

    private String[] originalCommandMsg;

    private Process[] processArray;

    private String[] outputs;

    private int[] exitValues;

    private WinBat() {
        super();
    }

    public static WinBat getInstance() {
        return new WinBat();
    }

    public String getIntegrationOutput() throws Exception {
        if (this.processArray == null) {
            throw new Exception("需要先执行命令后才能获取输出");
        }

        if (this.outputs == null) {
            // 获取操作系统(命令行)的字符集
            this.cmdCharset = Charset.forName((String) System.getProperties().get("sun.jnu.encoding"));
            this.outputs = new String[this.commandNum];
            InputStream inputStream;
            for (int index = 0; index < this.commandNum; ++index) {
                inputStream = this.processArray[index].getInputStream();
                // 将输出按行分成多个字符串。这原本不是想要的操作,但这没有办法
                var linesOutput = new BufferedReader(new InputStreamReader(
                        inputStream, this.cmdCharset)).lines();
                // 将每行字符串以换行符拼接,还原出原始信息
                this.outputs[index] = linesOutput.collect(Collectors.joining(System.lineSeparator()));
            }
        }

        var stream = Stream.of(this.outputs);
        // 多加一个空行作不同命令输出之间的分隔
        return stream.collect(Collectors.joining(System.lineSeparator() + System.lineSeparator()));
    }

    public String getIntegrationCommand() throws Exception {
        if (this.originalCommandMsg == null) {
            throw new Exception("还没有输入命令");
        }

        var stream = Stream.of(this.originalCommandMsg);
        return stream.collect(Collectors.joining(System.lineSeparator()));
    }

    public String[] getOriginalCommand() throws Exception {
        if (this.originalCommandMsg == null) {
            throw new Exception("还没有输入命令");
        }

        return this.originalCommandMsg;
    }

    /**
     * 如果调用本方法时,本方法会阻塞调用线程,直到命令执行结束
     *
     * @since 2021-12-21
     */
    public int[] getExitValues() throws Exception {
        if (this.processArray == null) {
            throw new Exception("需要先执行命令后才能获取退出码");
        }

        this.exitValues = new int[this.commandNum];
        for (int index = 0; index < this.commandNum; ++index) {
            this.exitValues[index] = this.processArray[index].waitFor();
        }

        return this.exitValues;
    }

    /**
     * 如果调用本方法时,本方法会阻塞调用线程,直到命令执行结束
     *
     * @since 2021-12-21
     */
    public int getLastExitValues() throws Exception {
        if (this.processArray == null) {
            throw new Exception("需要先执行命令后才能获取退出码");
        }

        var exitValues = this.getExitValues();
        return exitValues[this.commandNum - 1];
    }

    private WinBat exec(String[] originalCommand) throws Exception {
        this.outputs = null;
        this.originalCommandMsg = originalCommand;
        this.commandNum = originalCommand.length;
        this.processArray = new Process[this.commandNum];

        for (int index = 0; index < this.commandNum; ++index) {
            this.processArray[index] = WinCmd.getInstance()
                    .execute(this.originalCommandMsg[index]).getProcess();
        }

        return this;
    }

    public WinBat execute(String[] command) throws Exception {
        return this.exec(command);
    }
}

完整代码

  已上传至 GitHub 中,可免费下载:https://github.com/wangpaihovel/cmd_win

  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值