Process 获取子进程输入流、杀死子进程

目录

Process 进程概述

获取子进程输入流

杀死 Process 子进程

不加 cmd 直接打开的子进程

加 cmd 打开的子进程


Process 进程概述

1、ProcessBuilder.start 和 Runtime.exec  方法都可以开启一个本机进程,并返回 Process 子类的一个实例,Process 实例可控制进程并获得相关信息。

2、Process 类提供了执行从进程输入、执行输出到进程、等待进程完成、检查进程的退出状态以及销毁(杀掉)进程的方法。 

3、从 JDK 1.5开始, ProcessBuilder.start() 是创建 Process 的首选方式。 《Runtime 运行时类 执行 dos 、cmd 命令、VBS 脚本

获取子进程输入流

1、public abstract InputStream getInputStream() :获取子进程的输入流

2、输入流获得由该 Process 对象表示的进程的标准输出流。 

3、实现注意事项:对输入流进行缓冲是一个好主意。 返回连接到子进程正常输出的输入流。

public static void main(String[] args) {
    try {
        Runtime runtime = Runtime.getRuntime();
        Process process = runtime.exec("cmd /c dir %JAVA_HOME%",null);
        InputStream inputStream = process.getInputStream();
        InputStreamReader streamReader = new InputStreamReader(inputStream,"gbk");
        BufferedReader bufferedReader = new BufferedReader(streamReader);
        String readLine ;
        while ((readLine = bufferedReader.readLine())!=null){
            System.out.println(readLine);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

 

杀死 Process 子进程

1、public abstract void destroy() :杀掉子进程,强制终止此 Process 对象表示的子进程。 

2、public Process destroyForcibly():杀死子进程,此Process对象表示的子进程被强制终止。 此方法的默认实现调用destroy() ,因此可能不会强制终止进程。 强烈建议使用此类的具体实现来使用兼容实现覆盖此方法。这是1.8新增的方法,也是推荐方式

3、public boolean isAlive():测试这个Process代表的子 进程是否存活。 为true则表示此 Process对象表示的子进程尚未终止。 

不加 cmd 直接打开的子进程

1、如下所示,Runtime 调用本地的 PotPlayer 程序播放了一个视频,返回 Process 对象,Process 就代表着打开的 PotPlayer 子进程。休眠 5 秒之后判断 PotPlayer 子进程是否活着,如果活着则杀死它,即 关闭PotPlayer 程序

2、对于如下 cmdStr 这种没有加前缀"cmd /c"的写法,在杀死子进程时,是没有问题的,因为打开的时候,Process 就直接记录的是 PotPlayer.exe 程序

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by Administrator on 2018/6/27 0027.
 * 杀进程测试类
 */
public class ProcessTest {
    public static void main(String[] args) {
        try {
            String cmdStr = "D:\\PotPlayer\\PotPlayerMini.exe E:/wmx/zl2.mp4";
            Runtime runtime = Runtime.getRuntime();
            Process process = runtime.exec(cmdStr);
            Thread.sleep(5000);
            if (process.isAlive()){
                process.destroy();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

加 cmd 打开的子进程

1、cmdStr1、cmdStr2 :对于 exe 程序是不用加"cmd  /c"前缀就可以直接打开的,这种方式打开时,Process的destory()与destroyForcibly()方法能正常杀死子进程。而加了"cmd /c"前缀的cmdStr3、cmdStr4打开的文件或程序都是“杀不死”的

2、然而对于其它的大部分的 DOS 指令是必须借助 cmd.exe 程序的,cmdStr3、cmdStr4中 的 cmd 字符表示的就是 windows 系统目录中的程序 “C:\\Windows\\System32\\cmd.exe”

3、如下所示的 cmdStr3、cmdStr4 中要想打开普通的 word 文件,如 txt、ppt、excel、pdf、png、mp4 等等都是要借用 cmd.exe 程序才能打开的,否则会报错说找不到路径

4、cmdStr3、cmdStr4 这种直接指明参数文件,而没有指定打开此文件的程序时,默认会使用文件的关联程序进行打开,如下面的“E:/wmx/演讲稿.pptx”,如果关联的是Office则用Office打开,如果关联的是WPS,则用WPS打开。

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by Administrator on 2018/6/27 0027.
 * 杀进程测试类
 */
public class ProcessTest {
    public static void main(String[] args) {
        try {
            String cmdStr1 = "D:\\PotPlayer\\PotPlayerMini.exe E:/wmx/zl2.mp4";
            String cmdStr2 = "D:\\PotPlayer\\GPaoPao.exe";
            String cmdStr3 = "cmd /c E:/wmx/演讲稿.pptx";
            String cmdStr4 = "cmd /c E:/wmx/zl2.mp4";

            Runtime runtime = Runtime.getRuntime();
            Process process = runtime.exec(cmdStr4);
            Thread.sleep(5000);
            if (process.isAlive()) {
                process.destroy();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

5、加了"cmd  /c”前缀就表示会打开cmd.exe程序来执行后面的命令,所以cmdStr3、cmdStr4在执行之后任务管理器就会有cmd进程,于是当Process调用destory()或者destroyForcibly()杀子进程的时候,杀死的只是cmd.exe,而真正需要结束的是打开mp4文件的 PotPlayer,或者是打开 pptx 文件的 WPS 程序

解决方式 1

1、如果能准确知道打开文件的程序路径,则建议直接写上程序路径。如下所示直接指定打开 .docx 文件的 Office 程序,这样结束子进程的时候就不会有问题了。

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by Administrator on 2018/6/27 0027.
 * 杀进程测试类
 */
public class ProcessTest {
    public static void main(String[] args) {
        try {
            /** 当路径中有空格时,则应该程序和参数分开写*/
            String[] paramArr = new String[2];
            paramArr[0] = "C:\\Program Files (x86)\\Microsoft Office\\root\\Office16\\WINWORD.EXE";
            paramArr[1] = "E:\\wmx\\Map_in-depth.docx";
            Runtime runtime = Runtime.getRuntime();
            Process process = runtime.exec(paramArr);
            Thread.sleep(15000);
            if (process.isAlive()) {
                process.destroy();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

解决方式 2

1、因为很多时候可能并不知道某个文件到底将来会用什么程序打开,如.docx文件可能是Office打开,也可能是WPS打开

2、而且形如Office与WPS安装的路径也不一定知道或者路径不固定,此时采用杀进程树的方式来解决

3、因为加"cmd /c"前缀使用cmd.exe程序来执行命令时,是先打开了cmd程序,然后打开的文件关联程序打开文件,后者属于cmd.exe程序的子进程,它们属于同一个进程树,而cmd提供了杀死整个进程树的命令,taskkill

4、taskkill /PID xxx /F /T:taskkill表示杀死任务,/PID表示按进程的pid进行关闭,xxx表示进程pid值,/F表示强制终止进程,/T表示终止指定的进程和由它启用的子进程。

5、这种方式时借助 JNA 的 API 会更加方便,需要的 Jar 包以及相关知识可以参考《JNA 理论详解 1》《JNA 实战 1

6、使用 JNA 则先要导入它的两个开发包

package com.lct.utils;

import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.WinNT;

import java.lang.reflect.Field;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;

/**
 * Created by Administrator on 2018/6/26 0026.
 * 系统工具类
 */
public class SystemUtils {

    /**
     * 杀死指定进程数,即包括process进程的所有子进程
     *
     * @param process
     */
    public static void killProcessTree(Process process) {
        try {
            if (process != null && process.isAlive()) {
                Field f = process.getClass().getDeclaredField("handle");
                f.setAccessible(true);
                long handl = f.getLong(process);
                Kernel32 kernel = Kernel32.INSTANCE;
                WinNT.HANDLE handle = new WinNT.HANDLE();
                handle.setPointer(Pointer.createConstant(handl));
                int ret = kernel.GetProcessId(handle);
                Long PID = Long.valueOf(ret);
                String cmd = "cmd /c taskkill /PID " + PID + " /F /T ";
                Runtime rt = Runtime.getRuntime();
                Process killPrcess = rt.exec(cmd);
                killPrcess.waitFor();
                killPrcess.destroyForcibly();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
import com.lct.utils.SystemUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by Administrator on 2018/6/27 0027.
 * 杀进程测试类
 */
public class ProcessTest {
    public static void main(String[] args) {
        try {
            String cmdStr4 = "cmd /c E:\\wmx\\Map_in-depth.docx";
            Runtime runtime = Runtime.getRuntime();
            Process process = runtime.exec(cmdStr4);
            /** 休眠5秒后关闭子进程树*/
            Thread.sleep(5000);
            SystemUtils.killProcessTree(process);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

这样就能杀死打开.docx文件的程序了,亲测有效!

  • 9
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蚩尤后裔-汪茂雄

芝兰生于深林,不以无人而不芳。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值