在 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