后续业务可能需要在程序中运行指令, 所以这里简单探究了一下, 分别从win和linux两个平台进行研究, 又以为java是跨平台语言, 可能二者之间的区别应该只是返回内容与输入指令的不同. (还不是在win上开发)
1. 如何使用
-
Runtime.getRuntime().exec("notepad");
-
RuntimeUtil.exec("notepad");
// hutool了解了使用方法, 接下来探究几个问题.
2. 如何获取返回值
-
public static String execCMD(String command) { StringBuilder sb = new StringBuilder(); try { Process process = Runtime.getRuntime().exec(command); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream())); String line; while ((line = bufferedReader.readLine()) != null) { sb.append(line).append("\n"); } } catch (Exception e) { return e.toString(); } return sb.toString(); }
-
hutool中用法1:
String str = RuntimeUtil.execForStr("ipconfig");
-
hutool中用法2:
List<String> ss = RuntimeUtil.execForLines("ipconfig");
需要注意一点:
参数
command
: a string array containing the program and its arguments.以上所有的
command
并不是cmd命令行中的命令, 而是在运行窗口(win+r)可以运行的, 比如dir这个典型的cmd命令, 在win+r的运行窗口就不能运行. 可以使用cmd /c dir
来运行./c 是运行完不显示窗口, /k是运行完显示, 其他参数可在cmd指令中打出
cmd /?
查看
3. 模拟在取结果时候堵塞进程
-
代码
System.err.println(DateUtil.format(new Date(), DatePattern.NORM_DATETIME_MS_PATTERN)); System.err.println(RuntimeUtil.execForStr("ping 192.168.0.222 /n 2")); System.err.println(DateUtil.format(new Date(), DatePattern.NORM_DATETIME_MS_PATTERN));
-
输出:
2022-07-15 16:34:50.523 正在 Ping 192.168.0.222 具有 32 字节的数据: 来自 192.168.0.222 的回复: 字节=32 时间=49ms TTL=128 来自 192.168.0.222 的回复: 字节=32 时间=16ms TTL=128 192.168.0.222 的 Ping 统计信息: 数据包: 已发送 = 2,已接收 = 2,丢失 = 0 (0% 丢失), 往返行程的估计时间(以毫秒为单位): 最短 = 16ms,最长 = 49ms,平均 = 32ms 2022-07-15 16:34:51.575
-
结论
确实可以看到两个时间相差1s左右. 可以将
ping ** /n 2
中的2调大一些查看区别.接下来我们把ping命令换成
notepad
或cmd /c notepad
, 可以看到直接堵死了.在linux系统的终端运行firefox, 在终端会显示对应日志.
对应到我们例子中, 执行exec方法时候会有返回一个进程p,
我们就是从进程p的输入流中拿到的程序/指令返回的内容(写在命令行中的内容)
正常情况下程序执行完就自动结束了, 但是记事本/firefox不会自动停止,
所以线程会一直占用着, 与是否写日志无关.
如果这种情况下获取返回内容, 可以将返回内容写入全局数组
另外使用线程异步进行读取.
4. 刨析进程的从属关系
-
代码(放在接口中测试)
ThreadUtil.execAsync(() -> RuntimeUtil.execForStr("notepad")); ThreadUtil.execAsync(() -> RuntimeUtil.execForStr("ping 192.168.0.222 /t")); ThreadUtil.execAsync(() -> RuntimeUtil.execForStr("notepad"));
-
运行, 使用
Process Explorer
软件查看运行一次.
运行3次.
可以看到执行的这些都是
java.exe
的子线程, 那么当我们停止java.exe
程序时候, 其下的子程序也会一起被杀掉吗?其实不会, 这些线程会被移动到根目录下
这很疑惑, 接下来来一个对比类型, 打开命令行输入`ping localhost \t, 查看进程
可以看到cmd是在
explorer.exe
下的进程, 就是我们的资源管理器(包括桌面这些, 并不只是我的电脑),而且不同之处是
ping.exe
, 代码生成的会自带一个conhost
, 手动执行的则平级生成的.然后又测试了使用
Runtime.getRuntime().exec("ping 192.168.0.111 /t");
生成, 发现当关闭java.exe
时还是会移动到最后.手动杀掉java也不会影响(树影响), 但是手动命令行中启动的ping在只杀掉命令行时候会一同将子目录杀掉
尚未在实际中应用, 暂时到此为止.