每个 Java 应用程序都有一个 Runtime 类实例,使应用程序能够与其运行的环境相连接。可以通过 getRuntime 方法获取当前运行时。 应用程序不能创建自己的 Runtime 类实例。我们可以通过 Runtime.exec()用来执行外部程序或命令
Runtime.exec() 有四种调用方法
public Process exec(String command);
public Process exec(String [] cmdArray);
public Process exec(String command, String [] envp);
public Process exec(String [] cmdArray, String [] envp);
demo
下面通过一个Demo来 展示 如何用Java来调用Windows上的wmic命令来获取系统中当前的进程信息。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class RuntimeExecTest {
/**
* @param args
*/
public static void main(String[] args) {
test();
}
private static void test() {
//linux cmd命令
Runtime.getRuntime().exec(new String[]{"/bin/sh","-c","javap -l xxx > output.txt"});//通过bin/sh 解释执行该命令
//Windows cmd
// String[] cmd = new String[]{"shutdown" ,"-s" ,"-t" ,"3600"};//定时关机
String[] cmd = new String[]{"cmd" ,"-s" ,"-t" ,"3600"};//定时关机
// String[] cmd = new String[]{"cmd.exe", "/C", "wmic process get name"};
// 输出aaa到1.txt 然后 使用记事本打开该文件
String command = "cmd /c echo aaa >> d:\\1.txt && notepad d:\\1.txt";// && 命令之间需连接符连接
try {
Process process = Runtime.getRuntime().exec(command,null);
new Thread(new SerializeTask(process.getInputStream())).start();
new Thread(new SerializeTask(process.getErrorStream())).start();
process.getOutputStream().close();
int exitValue = process.waitFor();
System.out.println("返回值:" + exitValue);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 打印输出线程
*/
class SerializeTask implements Runnable {
private InputStream in;
public SerializeTask(InputStream in) {
this.in = in;
}
@Override
public void run() {
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(in));
String line = null;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (br != null)
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
注意事项
- 等待命令执行结束用waitFor(),其返回值就是命令的返回值。
- 如果出现程序执行被挂起,没有任何反应的情况,是由于没有读取命令子进程的正常输出流或错误输出流导致缓冲区被占满,进程被锁住。这个时候需要把输出流中的内容给读出来。最好的做法是使用两个线程,分别同时读取正常输出流和错误输出流。
- 执行Windows平台上的命令时使用
cmd.exe /C
,如cmd.exe /C dir
。 - 记得关闭命令子进程的输出流,通过
Process.getOutputStream().close()
,这样不会导致命令子进程被锁住。 - Runtime.exec() 不等同于直接执行command line命令。Runtime.exec()很有局限性,对有些命令不能直接把command line里的内容当作String参数传给exec().比如重定向等命令。举个例子:
javap -l xxx > output.txt
。这时要用到exec的第二种重载,即input 参数为String[]:Process p = Runtime.getRuntime().exec(new String[]{"/bin/sh","-c","javap -l xxx > output.txt"});//通过bin/sh 解释执行该命令
部分cmd命令需要cmd解释器来执行【在系统内不存在相应notepad.exe ping.exe等具体可执行文件】,所以java Runtime执行dir会报错,,需要使用cmd /c dir
/c
: 打开命令窗口执行完毕自动关闭
/k
:打开命令窗口执行完毕不自动关闭
可以通过win+R 打开测试 notepad 类型的命令是在系统内存在
notepad d:\1.txt
eg.通过命令行统计内存
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
public class 统计内存 {
/**
* @param args
*/
public static void main(String[] args) throws IOException {
test();
}
/**
* 统计每个进程占用多少内存
*
* @throws IOException
*/
private static void test() throws IOException {
// String command = "cmd /c tasklist | findstr svchost.exe";// 查看内存
String command = "cmd /c tasklist ";// 查看内存
try {
Process process = Runtime.getRuntime().exec(command, null);
SerializeTask target = new SerializeTask(process.getInputStream());
SerializeTask err = new SerializeTask(process.getErrorStream());
new Thread(target).start();//开启线程读取返回值
new Thread(err).start();//开启线程读取错误返回
process.getOutputStream().close();
int exitValue = process.waitFor();//等待结束
System.out.println(target.res);
//正则解析结果
Pattern compile = Pattern.compile("(.+)\\s+\\d+\\s+\\w+\\s+\\d\\s+(\\d.+K)");
Matcher matcher = compile.matcher(target.res);
int total = 0;
Map<String, Integer> map = new HashMap<>();
while (matcher.find()) {
int me = ConversionFormat(matcher.group(2));
total += me;
String name = matcher.group(1);
if (map.containsKey(name)) {
map.put(name, map.get(name) + me);
} else {
map.put(name, me);
}
}
System.out.println("总共占用内存 " + total);
System.out.println("=================");
System.out.println(map);
//解析结果结束
System.out.println("运行返回值:" + exitValue);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 转换数据格式 7,752 K 7752
*
* @param group
* @return
*/
private static int ConversionFormat(String group) {
String replace = group.replace(",", "");
String replace1 = replace.replace(" K", "");
return Integer.parseInt(replace1) / 1024;
}
}
/**
* 打印输出线程
*/
class SerializeTask implements Runnable {
private InputStream in;
String res = "";
public SerializeTask(InputStream in) {
this.in = in;
}
@Override
public void run() {
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(in, "gbk"));
String line = null;
while ((line = br.readLine()) != null) {
// System.out.println(line);
res = res + line + "\r\n";
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (br != null) {
br.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}