2023年11月29日发(作者:)

java打开本地应⽤程序(调⽤cmd---Runtime⽤法详解

有时候我们需要借助java程序打开电脑⾃带的⼀些程序,可以直接打开或者借助cmd命令窗⼝打开⼀些常⽤的应⽤程序或者脚本,在cmd窗⼝执⾏的命令都可以通

过这种⽅式运⾏。

例如:

package ;

import ption;

import ;

public class TestCmd {

@Test

public void test1() throws IOException {

// 直接打开应⽤程序

time().exec("C:/Users/liqiang/Desktop/开机后点它.bat"); // 打开⼀个批处理⽂件

time().exec("E:/酷狗/KGMusic/"); // 打开酷狗

/******** 可以通过cmd命令打开软件或者是做其他 *****/

time().exec("C:/Windows/System32/ /k start E:/酷狗/KGMusic/"); // 通过cmd窗⼝执⾏命令

time().exec("C:/Windows/System32/ /k start E:/php/Test/第⼀个html/界⾯.html"); // 通过cmd命令打开⼀个⽹页

time().exec("C:/Windows/System32/ /k mkdir C:UsersliqiangDesktopjava键的1"); // 通过cmd创建⽬录⽤两个反斜杠

time().exec("C:/Windows/System32/ /k mkdir C:UsersliqiangDesktopjava键的2"); // 通过cmd创建⽬录⽤两个反斜杠

time().exec("C:/Windows/System32/ /c calc ");// 通过cmd打开计算器

}

@Test

public void test2() throws IOException {

/******** 可以通过cmd命令打开软件或者是做其他 *****/

time().exec("C:/Windows/System32/ /c osk");// 通过屏幕软键盘

}

}

另外也可以获取⼀些其他的JVM参数:

long totalMemory = time().totalMemory();//总内存

long freeMemory = time().freeMemory();//剩余内存

long maxMemory = time().maxMemory();//最⼤内存

n(totalMemory/1024/1024+"MB");

n(freeMemory/1024/1024+"MB");

n(maxMemory/1024/1024+"MB");

也可以直接执⾏⼀些命令:

time().exec("calc");//打开计算器

补充:上⾯的⽅式都是异步运⾏的⽅式,也就是在执⾏命令之后会不等exec执⾏完就执⾏下⼀条语句,为了实现同步结果,或者为了获取返回的结果,参考:

import ption;

import tream;

import ;

import Factory;

public final class Test {

private static final Logger logger = ger(Test.class);

public static void main(String[] args) throws NullPointerException {

long start = tTimeMillis();

String srcPath = "C:/Users/liqiang/Desktop/ww/", desPath = "C:/Users/liqiang/Desktop/ww";

String command = "";

String osName = perty("");

if (ns("Windows")) {

command = "soffice --headless --convert-to pdf " + srcPath + " --outdir " + desPath;

exec(command);

}

long end = tTimeMillis();

("⽤时:{} ms", end - start);

}

public static boolean exec(String command) {

Process process;// Process可以控制该⼦进程的执⾏或获取该⼦进程的信息

try {

("exec cmd : {}", command);

process = time().exec(command);// exec()⽅法指⽰Java虚拟机创建⼀个⼦进程执⾏指定的可执⾏程序,并返回与该⼦进程对应的Process对象实例。

// 下⾯两个可以获取输⼊输出流

InputStream errorStream = orStream();

InputStream inputStream = utStream();

} catch (IOException e) {

(" exec {} error", command, e);

return false;

}

int exitStatus = 0;

try {

exitStatus = r();// 等待⼦进程完成再往下执⾏,返回值是⼦线程执⾏完毕的返回值

// 第⼆种接受返回值的⽅法

int i = lue(); // 接收执⾏完毕的返回值

("i----" + i);

} catch (InterruptedException e) {

("InterruptedException exec {}", command, e);

return false;

}

if (exitStatus != 0) {

("exec cmd exitStatus {}", exitStatus);

} else {

("exec cmd exitStatus {}", exitStatus);

}

y(); // 销毁⼦进程

process = null;

return true;

}

}

补充:runtime执⾏的时候也可以获取其输出流与错误的输出流,也就是每次在调⽤runtime的时候⽐较耗时,其会创建⼀个

Process,并且伴随着两个流。(InputStream可以获取到类似于在cmd运⾏的时候获取到的信息,这在⽤java写⼀些脚本的时候

⾮常有⽤)

package ;

import edReader;

import ption;

import tream;

import treamReader;

public class MyTest {

public static void main(String[] args) {

try {

Process pop = time()

.exec("E:/weblogic12.1.3/user_projects/domains/base_domain/");

// 获取其正常的输出流

InputStream inputStream = utStream();

InputStreamReader inputStreamReader = new InputStreamReader(inputStream);

BufferedReader br = new BufferedReader(inputStreamReader);

String line = null;

while ((line = ne()) != null) {

n(line);

}

// 获取其错误的输出流

InputStream errorStream = orStream();

InputStreamReader errorStreamReader = new InputStreamReader(errorStream);

BufferedReader errorBr = new BufferedReader(errorStreamReader);

String errorLine = null;

while ((errorLine = ne()) != null) {

n("err:" + errorLine);

}

r();

} catch (IOException | InterruptedException e) {

tackTrace();

}

}

}

结果:

.

.

JAVA Memory arguments: -Xms256m -Xmx512m -XX:CompileThreshold=8000 -XX:PermSize=128m -XX:MaxPermSize=256m

.

CLASSPATH=C:PROGRA~1JavaJDK17~1.0_;E:WEBLOG~1.3wlserverserverlibweblogic_;E:WEBLOG~;E:WEBLOG~1.3oracle_

.

PATH=;E:WEBLOG~1.3wlserverservernativewinx64;E:WEBLOG~1.3wlserverserverbin;E:WEBLOG~1.3oracle__1.9.2bin;C:PROGRA~1JavaJDK1

.

***************************************************

* To start WebLogic Server, use a username and *

* password assigned to an admin-level user. For *

.......

补充:Runtime也可以获取系统的CPU数量

time().availableProcessors()

调⽤cmd的时候中间的的/c/kcm的参数,windows下查看参数说明:/k参数可以执⾏完窗⼝停留

C:Usersliqiang>cmd/?

启动 Windows 命令解释器的⼀个新实例

CMD [/A | /U] [/Q] [/D] [/E:ON | /E:OFF] [/F:ON | /F:OFF] [/V:ON | /V:OFF]

[[/S] [/C | /K] string]

/C 执⾏字符串指定的命令然后终⽌

/K 执⾏字符串指定的命令但保留

/S 修改 /C /K 之后的字符串处理(见下)

/Q 关闭回显

/D 禁⽌从注册表执⾏ AutoRun 命令(见下)

/A 使向管道或⽂件的内部命令输出成为 ANSI

/U 使向管道或⽂件的内部命令输出成为

Unicode

/T:fg 设置前台/背景颜⾊(详细信息见 COLOR /?)

/E:ON 启⽤命令扩展(见下)

/E:OFF 禁⽤命令扩展(见下)

/F:ON 启⽤⽂件和⽬录名完成字符(见下)

/F:OFF 禁⽤⽂件和⽬录名完成字符(见下)

/V:ON 使⽤ ! 作为分隔符启⽤延迟的环境变量

扩展。例如,/V:ON 会允许 !var! 在执⾏时

扩展变量 varvar 语法会在输⼊时

扩展变量,这与在⼀个 FOR

循环内不同。

/V:OFF 禁⽤延迟的环境扩展。

注意,如果字符串加有引号,可以接受⽤命令分隔符 "&&"

分隔多个命令。另外,由于兼容性

原因,/X /E:ON 相同,/Y /E:OFF 相同,且 /R

/C 相同。任何其他开关都将被忽略。

如果指定了 /C /K,则会将该开关之后的

命令⾏的剩余部分作为⼀个命令⾏处理,其中,会使⽤下列逻辑

处理引号(")字符:

1. 如果符合下列所有条件,则会保留

命令⾏上的引号字符:

- 不带 /S 开关

- 正好两个引号字符

补充:time().addShutdownHook(thread); ⽅法 可以添加⼀个钩⼦,在Java 进程结束的时候会调⽤钩⼦中的线程。实际原理是最后⼀个⾮守护线程死亡

的时候会开启DestroyJavaVM 调⽤相关⽅法,最终调⽤time().addShutdownHook(thread); 的线程的start() ⽅法开启线程, 执⾏线程的任务。

例如: 测试在线程开始和结束的时候打印⾮守护线程信息。

public class PlainTest {

public static void main(String[] args) throws InterruptedException {

// 打印所有的线程

printThread();

n("====");

Thread thread = new Thread(() -> {

n("JVM 进程结束了 1~~~");

printThread();

try {

(5 * 1000);

} catch (InterruptedException e) {

tackTrace();

}

n("JVM 进程结束了 2~~~");

});

e("testName");

time().addShutdownHook(thread);

n("111222");

}

private static void printThread() {

n("====== 开始打印⾮守护线程");

ThreadGroup currentGroup =

tThread().getThreadGroup();

int noThreads = Count();

Thread[] lstThreads = new Thread[noThreads];

ate(lstThreads);

for (int i = 0; i < noThreads; i++) {

if (!lstThreads[i].isDaemon()) {

n("线程号:" + i + " = " + lstThreads[i].getName());

}

}

n("====== 结束打印⾮守护线程");

}

}

可以看到我们只创建了⼀个线程,然后调⽤time().addShutdownHook(thread); 缓存起来。 我们并没有调⽤start⽅法开启线程。另外, 如果不想添

加这样的钩⼦⽅法可以调⽤ time().removeShutdownHook(thread); 进⾏移除。

结果:

====== 开始打印⾮守护线程

线程号:0 = main

====== 结束打印⾮守护线程

====

111222

JVM 进程结束了 1~~~

====== 开始打印⾮守护线程

线程号:0 = DestroyJavaVM

线程号:1 = testName

====== 结束打印⾮守护线程

JVM 进程结束了 2~~~

1. 原理查看:

(1) e#addShutdownHook

public void addShutdownHook(Thread hook) {

SecurityManager sm = urityManager();

if (sm != null) {

ermission(new RuntimePermission("shutdownHooks"));

}

(hook);

}

(2) ationShutdownHooks#add

private static IdentityHashMap hooks;

static {

try {

(1 /* shutdown hook invocation order */,

false /* not registered if shutdown in progress */,

new Runnable() {

public void run() {

runHooks();

}

}

);

hooks = new IdentityHashMap<>();

} catch (IllegalStateException e) {

// application shutdown hooks cannot be added if

// shutdown is in progress.

hooks = null;

}

}

static void runHooks() {

Collection threads;

synchronized(ApplicationShutdownHooks.class) {

threads = ();

hooks = null;

}

for (Thread hook : threads) {

();

}

for (Thread hook : threads) {

while (true) {

try {

();

break;

} catch (InterruptedException ignored) {

}

}

}

}

static synchronized void add(Thread hook) {

if(hooks == null)

throw new IllegalStateException("Shutdown in progress");

if (e())

throw new IllegalArgumentException("Hook already running");

if (nsKey(hook))

throw new IllegalArgumentException("Hook previously registered");

(hook, hook);

}

可以看到其核⼼设计是将线程放到了ationShutdownHooks#hooks 内部。 同时静态代码块调⽤ wn#add 添加⼀个任务

(3) wn 是⼀个重要的类,

package ;

class Shutdown {

/* Shutdown state */

private static final int RUNNING = 0;

private static final int HOOKS = 1;

private static final int FINALIZERS = 2;

private static int state = RUNNING;

/* Should we run all finalizers upon exit? */

private static boolean runFinalizersOnExit = false;

// The system shutdown hooks are registered with a predefined slot.

// The list of shutdown hooks is as follows:

// (0) Console restore hook

// (1) Application hooks

// (2) DeleteOnExit hook

/* Invoked by alizersOnExit */

static void setRunFinalizersOnExit(boolean run) {

synchronized (lock) {

runFinalizersOnExit = run;

}

}

/**

* Add a new shutdown hook. Checks the shutdown state and the hook itself,

* but does not do any security checks.

*

* The registerShutdownInProgress parameter should be false except

* registering the DeleteOnExitHook since the first file may

* be added to the delete on exit list by the application shutdown

* hooks.

*

* @params slot the slot in the shutdown hook array, whose element

* will be invoked in order during shutdown

* @params registerShutdownInProgress true to allow the hook

* to be registered even if the shutdown is in progress.

* @params hook the hook to be registered

*

* @throw IllegalStateException

* if registerShutdownInProgress is false and shutdown is in progress; or

* if registerShutdownInProgress is true and the shutdown process

* already passes the given slot

*/

static void add(int slot, boolean registerShutdownInProgress, Runnable hook) {

synchronized (lock) {

if (hooks[slot] != null)

throw new InternalError("Shutdown hook at slot " + slot + " already registered");

if (!registerShutdownInProgress) {

if (state > RUNNING)

throw new IllegalStateException("Shutdown in progress");

} else {

if (state > HOOKS || (state == HOOKS && slot <= currentRunningHook))

throw new IllegalStateException("Shutdown in progress");

}

hooks[slot] = hook;

}

}

/* Run all registered shutdown hooks

*/

private static void runHooks() {

* response to SIGINT, SIGTERM, etc.

*/

private static void sequence() {

synchronized (lock) {

/* Guard against the possibility of a daemon thread invoking exit

* after DestroyJavaVM initiates the shutdown sequence

*/

if (state != HOOKS) return;

}

runHooks();

boolean rfoe;

synchronized (lock) {

state = FINALIZERS;

rfoe = runFinalizersOnExit;

}

if (rfoe) runAllFinalizers();

}

/* Invoked by , which does all the security checks.

* Also invoked by handlers for system-provided termination events,

* which should pass a nonzero status code.

*/

static void exit(int status) {

boolean runMoreFinalizers = false;

synchronized (lock) {

if (status != 0) runFinalizersOnExit = false;

switch (state) {

case RUNNING: /* Initiate shutdown */

state = HOOKS;

break;

case HOOKS: /* Stall and halt */

break;

case FINALIZERS:

if (status != 0) {

/* Halt immediately on nonzero status */

halt(status);

} else {

/* Compatibility with old behavior:

* Run more finalizers and then halt

*/

runMoreFinalizers = runFinalizersOnExit;

}

break;

}

}

if (runMoreFinalizers) {

runAllFinalizers();

halt(status);

}

synchronized (Shutdown.class) {

/* Synchronize on the class object, causing any other thread

* that attempts to initiate shutdown to stall indefinitely

*/

beforeHalt();

sequence();

halt(status);

}

}

/* Invoked by the JNI DestroyJavaVM procedure when the last non-daemon

* thread has finished. Unlike the exit method, this method does not

* actually halt the VM.

*/

static void shutdown() {

synchronized (lock) {

switch (state) {

case RUNNING: /* Initiate shutdown */

state = HOOKS;

break;

case HOOKS: /* Stall and then return */

case FINALIZERS:

这个在Spring 容器中有使⽤,容器使⽤这个钩⼦实现容器销毁时候相关对象调⽤销毁⽅法 ableBean#destroy ⽅法。

注意: kill 信号能捕捉到,kill -9 的时候shutdown 添加的线程⽆效

(1) 测试代码:

import ownLatch;

public class PlainTest {

public static void main(String[] args) throws InterruptedException {

CountDownLatch countDownLatch = new CountDownLatch(1);

time().addShutdownHook(new Thread(() -> {

n("tdownHook");

}));

();

}

}

测试结果:

/*******kill **/

[root@localhost test]# java PlainTest

tdownHook

/****kill -9 pid***/

[root@localhost test]# java PlainTest

Killed

(2) 可以⾃⼰捕捉⼀些信号做处理

1 linux 查看⽀持的信号

[root@localhost test]# kill -l

1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP

6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1

11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM

16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP

21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ

26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR

31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3

38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8

43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13

48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12

53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7

58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2

63) SIGRTMAX-1 64) SIGRTMAX

2》编写信号处理代码

import ;

import Handler;

import ownLatch;

public class PlainTest implements SignalHandler {

private void signalCallback(Signal sn) {

n(e() + " is recevied.");

// 退出程序

(0);

}