cyn's blog cyn's blog
首页
  • java开发知识
  • 开发问题记录
  • 计算机网络
  • 数据结构与算法
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 学习
  • 面试
  • 实用技巧
个人简历
GitHub (opens new window)
首页
  • java开发知识
  • 开发问题记录
  • 计算机网络
  • 数据结构与算法
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 学习
  • 面试
  • 实用技巧
个人简历
GitHub (opens new window)
  • java技术

    • Java 快读快输出
    • 自定义比较器
    • session和token有什么区别?
    • HashMap为什么比数组查询快
    • int和Integer区别详解
    • String和StringBuffer
    • 接口和抽象类区别
    • 小数计算都是不精确的
    • 判断数组、字符串、集合为空和null
    • 布隆过滤器
    • Java实体类实现Serializable接口?(序列化)
    • java.util.Arrays.asList()
    • URI_URL
    • volatile和synchronized的区别
    • Nginx+Tomcat实现负载均衡、动静分离集群
    • nginx常用命令
  • 开发问题记录

    • 关闭端口号占用的进程
    • 前后端跨域问题
    • java调用外部程序Runtime.getRuntime().exec
      • 静态资源映射,访问、上传到服务器本地
    • java开发
    • 开发问题记录
    cyn
    2023-04-26
    目录

    java调用外部程序Runtime.getRuntime().exec

    Runtime.getRuntime().exec()用于调用外部可执行程序或系统命令,并重定向外部程序的标准输入、标准输出和标准错误到缓冲池。

    Process process = Runtime.getRuntime().exec( ".//p.exe ");
    process.waitfor();//等待子进程完成再往下执行
    
    1
    2

    Runtime.getRuntime() 返回当前应用程序的Runtime对象,该对象的 exec() 方法指示Java虚拟机创建一个子进程执行指定的可执行程序,并返回与该子进程对应的Process对象实例。通过Process可以控制该子进程的执行或获取该子进程的信息。

    # exec方法

    Runtime.getRuntime().exec共有六个重载方法:

    // 在单独的进程中执行指定的外部可执行程序的启动路径或字符串命令
    public Process exec(String command)
    // 在单独的进程中执行指定命令和变量
    public Process exec(String[] cmdArray)
    // 在指定环境的独立进程中执行指定命令和变量
    public Process exec(String command, String[] envp)
    // 在指定环境的独立进程中执行指定的命令和变量
    public Process exec(String[] cmdArray, String[] envp)
    // 在指定环境和工作目录的独立进程中执行指定的字符串命令
    public Process exec(String command, String[] envp, File dir)
    // 在指定环境和工作目录的独立进程中执行指定的命令和变量
    public Process exec(String[] cmdarray, String[] envp, File dir)
    // 参数说明:
    	cmdarray // 包含所调用命令及其参数的数组。数组第一个元素是命令,其余是参数
    	envp	 // 字符串数组,其中每个元素的环境变量的设置格式为 name=value,如果子进程应该继承当前进程的环境,则该参数为null
    	dir		 // 子进程的工作目录;如果子进程应该继承当前进程的工作目录,则该参数为null
        
    // 参数cmdArray 示例:shutdown -s -t 3600
    String arr[] = {"shutdown","-s","-t","3600"};
    Process process = Runtime.getRuntime().exec(arr[]);
    /*
    注意:
    	在调用这个方法时,不能将命令和参数放在一起,eg:String arr[] = {"shutdown -s -t 3600"};
    	这样会导致程序把“shutdown -s -t 3600”当成是一条命令的名称,然后去查找“shutdown -s -t 3600”这条命令,它当然会找不到,所以就会报错
    */
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25

    注意:Runtime.exec() 不是cmd或shell环境,因此无法直接调用dir等命令,需要在程序中读取运行的操作系统平台,以调用不同的命令解释器(NT:cmd.exe,windows 95/98:command.exe,linux:/bin/sh)

    # Process 的常用方法

    Procss类将持有该程序返回 JVM 的引用。这个procss类是一个抽象类,具体子类的实现依赖于不同的底层操作系统。

    // 导致当前线程等待,如有必要,一直要等到由该 Process 对象表示的进程已经终止。
    int waitFor()
    /*	如果已终止该子进程,此方法立即返回。
    	如果没有终止该子进程,调用的线程将被阻塞,直到退出子进程,0 表示正常终止 */
    
    // 杀掉子进程
    void destroy()
    
    // 返回子进程的出口值,值 0 表示正常终止
    int exitValue()
    
    // 获取子进程的错误流
    InputStream getErrorStream()
    // 获取子进程的输入流
    InputStream getInputStream()
    // 获取子进程的输出流
    OutputStream getOutputStream()
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17

    # 程序阻塞问题

    通过 Process实例.getInputStream() 和 Process实例.getErrorStream() 获取的输入流和错误信息流是缓冲池向当前Java程序提供的,而不是直接获取外部程序的标准输出流和标准错误流。 而缓冲池的容量是一定的,因此若外部程序在运行过程中不断向缓冲池输出内容,当缓冲池填满,那么外部程序将暂停运行直到缓冲池有空位可接收外部程序的输出内容为止。(采用xcopy命令复制大量文件时将会出现该问题)

    解决办法:当前的Java程序不断读取缓冲池的内容,从而腾出缓冲池的空间。

    Runtime r = Runtime.getRuntime();
    try{
        Process proc = r.exec("cmd /c dir"); // 假设该操作造成大量内容输出
      	// 采用字符流读取缓冲池内容,腾出空间
      	BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream(), "gbk")));
      	String line = null;
      	while ((line = reader.readLine()) != null){
      	   System.out.println(line);
      	}
     	
      	/* 或采用字节流读取缓冲池内容,腾出空间
      	 ByteArrayOutputStream pool = new ByteArrayOutputStream();
      	 byte[] buffer = new byte[1024];
      	 int count = -1;
      	 while ((count = proc.getInputStream().read(buffer)) != -1){
      	   pool.write(buffer, 0, count);
      	   buffer = new byte[1024];
      	 }
      	 System.out.println(pool.toString("gbk"));
      	 */
     	
      	int exitVal = proc.waitFor();
      	System.out.println(exitVal == 0 ? "成功" : "失败");
    }
    catch(Exception e){
      	e.printStackTrace();
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27

    注意:外部程序在执行结束后需自动关闭,否则不管是字符流还是字节流均由于既读不到数据,又读不到流结束符,从而出现阻塞Java进程运行的情况。cmd的参数 “/c” 表示当命令执行完成后关闭自身。

    # 拓展

    1,调用一次exec方法执行多条cmd命令,使用 && 分隔命令,该方法的局限性是只能在cmd里面使用

    Runtime.getRuntime().exec("cmd /c set CLASSPATH=D:\\ && javac D:\\a.java && java a");
    
    
    String arr[] = {"CLASSPATH=D://","Path=C:\\Program Files\\Java\\jdk1.8.0_131\\bin"};
    Runtime.getRuntime().exec("cmd /c javac a.java && java a", arr, new File("D://"));
    
    1
    2
    3
    4
    5

    2,执行Runtime.exec()需要注意的陷阱:https://www.cnblogs.com/fpqi/p/9679039.html (opens new window)

    编辑 (opens new window)
    上次更新: 2023/05/26, 15:58:27
    前后端跨域问题
    静态资源映射,访问、上传到服务器本地

    ← 前后端跨域问题 静态资源映射,访问、上传到服务器本地→

    Theme by Vdoing | Copyright © 2023-2023 cyn | MIT License
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式