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;
    }
}
  • 结果
    image

posted on 2023-11-29 10:38  C_C_菜园  阅读(128)  评论(0编辑  收藏  举报

导航