Process-与操作系统中的进程进行交互
1、Process介绍
在Java中,Process类是一个抽象类,它提供了与操作系统中的进程进行交互的方法。当你在Java程序中启动一个新的进程(例如,运行一个外部程序或脚本)时,JVM会创建一个Process实例来代表这个新的进程。
Process类提供了以下主要的方法:
- getInputStream():获取进程的标准输出流。你可以从这个流中读取进程的输出。
- getErrorStream():获取进程的错误输出流。你可以从这个流中读取进程的错误输出。
- getOutputStream():获取进程的标准输入流。你可以向这个流中写入数据,作为进程的输入。
- waitFor():等待进程结束,并返回进程的退出状态码。
- exitValue():获取进程的退出状态码。如果进程还没有结束,这个方法会抛出IllegalThreadStateException。
- destroy():强制结束进程。
以下是一个使用Process类的例子,它启动一个新的进程来运行ping命令:
Process process = Runtime.getRuntime().exec("ping www.google.com"); BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); String line; while ((line = reader.readLine()) != null) { System.out.println(line); } process.waitFor();
在这个例子中,我们首先使用Runtime.exec方法启动一个新的进程来运行ping命令。然后,我们创建一个BufferedReader来读取进程的输出。最后,我们使用Process.waitFor方法等待进程结束。
2、使用
- 使用Runtime.getRuntime().exec("java -c"),相当于调用三方库(三方程序)
- Runtime.getRuntime().exec()
Runtime.getRuntime().exec(参数1) 参数1是:执行的命令 Runtime.getRuntime().exec(参数1,参数2,参数3) 参数1是:执行的命令 参数3是:程序执行的文件夹,如:/phantomjs211/linux/bin
3、获取执行进程的pid(jdk8)
3.0、Java 9及更高版本,可以直接获取。
Process process = Runtime.getRuntime().exec("some-command"); long pid = process.pid(); System.out.println("PID: " + pid);
3.1、JNA、JNA和Process
- Java Native Access (JNA)库
Java Native Access (JNA) 是一个开源的Java库,它允许Java程序调用C和C++编写的本地应用程序接口(API)和库,而无需使用Java Native Interface (JNI) 或编写任何本地代码。
在传统的JNI使用中,Java开发者需要编写本地方法的Java声明,然后使用特定的工具生成C或C++的头文件,接着在这些头文件中实现本地方法。这个过程相当复杂,需要对C或C++有一定的了解,而且还需要处理本地代码的编译和分发。
相比之下,JNA大大简化了这个过程。使用JNA,你只需要在Java代码中声明本地方法的接口,然后JNA会自动处理与本地代码的交互,包括参数的转换和内存的管理。这意味着你可以直接在Java代码中调用本地方法,而无需编写或理解任何C或C++代码。
例如,假设你有一个C库,它提供了一个名为doSomething的函数。在JNI中,你需要编写C代码来实现一个与doSomething对应的本地方法。但在JNA中,你只需要声明一个接口,如下所示:
- JNA和Process的关系、区别
Process类和Java Native Access (JNA)库都是Java中与本地系统交互的方式,但它们的用途和工作方式有所不同。
Process类是Java标准库的一部分,它用于创建和控制操作系统的进程。你可以使用Process类来执行外部命令,然后获取命令的输出或错误信息,或者控制命令的输入。Process类提供了一种简单的方式来与操作系统的shell交互,但它的功能相对有限,主要限于启动新的进程和与这些进程进行简单的交互。
Java Native Access (JNA)库则提供了一种更直接和强大的方式来与本地系统交互。使用JNA,你可以直接调用操作系统的API,或者使用其他本地库。这意味着你可以在Java代码中使用本地系统的所有功能,而不仅仅是启动新的进程。然而,使用JNA通常需要对本地系统的API有一定的了解,而且JNA的使用也比Process类更复杂。
总的来说,Process类和JNA库都是Java中与本地系统交互的工具,但它们的功能和使用场景有所不同。
Process类主要用于启动和控制新的进程,而JNA库则提供了一种更直接和强大的方式来使用本地系统的API和库。
3.2、导包(gradle)
// implementation 'net.java.dev.jna:jna:5.12.1' implementation 'net.java.dev.jna:jna-platform:5.12.1'
3.3、工具类-测试
package com.cc.urlgethtml.utils; import com.sun.jna.Platform; import com.sun.jna.Pointer; import com.sun.jna.platform.win32.Kernel32; import com.sun.jna.platform.win32.WinNT; import java.io.BufferedReader; import java.io.File; import java.io.InputStream; import java.io.InputStreamReader; import java.lang.reflect.Field; import java.util.Objects; import java.util.Optional; /** * <p>JnaPlatform:获取执行命令的pid</p> * * @author CC * @since 2023/11/6 */ public class JnaPlatform { public static void main(String[] args) { Process process = null; try { //执行命令 if (Platform.isWindows()) { process = Runtime.getRuntime().exec("java -version", new String[]{}, new File("D:\\")); }else { process = Runtime.getRuntime().exec("ls -l"); } //获取日志 InputStream inputStream = process.getErrorStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); String msg; while ((msg = reader.readLine()) != null) { System.out.println(msg); } //获取pid Optional<Integer> pid = getPid(process); System.out.println("pid----" + pid.orElse(-1)); }catch(Exception e){ throw new RuntimeException(e.getMessage()); }finally { if (Objects.nonNull(process)) { process.destroy(); } } } /** <p>获取pid<p> * @param process process * @return {@link Optional<Integer>} * @since 2023/11/6 * @author CC **/ public static Optional<Integer> getPid(Process process) { if (Platform.isLinux()) { /* Linux platform */ try { Field pidField = process.getClass().getDeclaredField("pid"); pidField.setAccessible(true); return Optional.of((Integer) pidField.get(process)); } catch (NoSuchFieldException | IllegalAccessException e) { return Optional.empty(); } } else if (Platform.isWindows()) { /* Windows platform */ try { Field handleField = process.getClass().getDeclaredField("handle"); handleField.setAccessible(true); long handl = (Long) handleField.get(process); Kernel32 kernel = Kernel32.INSTANCE; WinNT.HANDLE hand = new WinNT.HANDLE(); hand.setPointer(Pointer.createConstant(handl)); int pid = kernel.GetProcessId(hand); return Optional.of(pid); } catch (NoSuchFieldException | IllegalAccessException e) { return Optional.empty(); } } return Optional.empty(); } /** <p>根据pid停止进程-待实现<p> * @since 2023/11/6 * @author CC **/ public boolean kill(String pId){ return true; } }
- 结果
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)