-
有时候在Java程序中需要调用linux命令或shell脚本,而java.lang.Runtime类中的exec()方法支持此操作。
-
名词解释
java.lang.Runtime1 》每个Java应用程序都有一个Runtime类的Runtime ,允许应用程序与运行应用程序的环境进行链接。 当前运行时可以从getRuntime方法获得。
2 》应用程序无法创建自己的此类的实例。java.lang.Process
1 》ProcessBuilder.start()和Runtime.exec方法创建一个本机进程,并返回一个Process子类的Process ,可以用来控制进程并获取有关它的信息。 Process类提供了用于执行进程输入,执行输出到进程,等待进程完成,检查进程的退出状态以及销毁(杀死)进程的方法。
2 》创建进程的方法可能不适用于某些本机平台上的特殊进程,例如本机窗口进程,守护进程,Microsoft Windows上的Win16 / DOS进程或shell脚本。
3 》默认情况下,创建的子进程没有自己的终端或控制台。 其所有的标准I / O(即标准输入,标准输出,标准错误)操作将被重定向到父进程,在那里他们可以经由使用所述方法获得的流进行访问getOutputStream() , getInputStream()和getErrorStream() 。 父进程使用这些流将输入提供给子进程并从子进程获取输出。 因为一些本地平台只为标准输入和输出流提供有限的缓冲区大小,因此无法及时写入输入流或读取子进程的输出流可能导致子进程阻塞甚至死锁。
4 》在需要的时候, subprocess I/O can also be redirected使用ProcessBuilder类的方法。
5 》当不再有对Process对象的引用时,子进程不会被杀死,而是子进程继续异步执行。
6 》不要求Process对象表示的进程与拥有Process对象的Java进程Process执行或同时执行。
7 》从1.5开始, ProcessBuilder.start()是创建Process的首选方式。 -
使用示例:
Runtime rt = Runtime.getRuntime(); Process proc = rt.exec("javac");
而Process的返回状态可以通过两个方法获取
proc.exitValue()返回子进程的退出值。由Process对象表示的子进程的退出值。 按照惯例,值0表示正常终止。
proc.waitFor()
导致当前线程等待,如有必要,直到由此Process对象表示的进程已终止。 如果子进程已经终止,此方法将立即返回。 如果子进程尚未终止,则调用线程将被阻止,直到子进程退出。
由此Process对象表示的子进程的退出值。 根据惯例,值0表示正常终止。 -
标准示例:
主类,调用linux命令的逻辑方法package com.example.demo.runtme; /** * 主类,调用linux命令的逻辑方法 * @author jinsx * @date 2019/8/30 11:00 */ public class BusinessClass { public static void main(String args[]) { try { Runtime rt = Runtime.getRuntime(); // 执行命令 Process proc = rt.exec("java com.example.demo.runtme.AuxiliaryClass 'Hello World'"); // 错误信息 StreamOutput error = new StreamOutput(proc.getErrorStream(), "ERROR"); // 输出信息(Runtime的输出,即Process的输入) StreamOutput output = new StreamOutput(proc.getInputStream(), "OUTPUT"); // 启动执行 error.start(); output.start(); // 子进程退出状态,0表示正常终止 int exitVal = proc.waitFor(); System.out.println("ExitValue: " + exitVal); } catch (Throwable t) { t.printStackTrace(); } } }
辅助类
package com.example.demo.runtme; import java.util.Arrays; /** * 辅助类 * @author jinsx * @date 2019/8/30 10:33 */ public class AuxiliaryClass { public static void main(String[] args) { if (args.length < 1) { System.out.println("AuxiliaryClass no parameter"); return; } System.out.println("AuxiliaryClass parameter is : "); Arrays.asList(args).stream().forEach(System.out::println); } }
解决:因为一些本地平台只为标准输入和输出流提供有限的缓冲区大小,因此无法及时写入输入流或读取子进程的输出流可能导致子进程阻塞甚至死锁。
package com.example.demo.runtme; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; /** * 解决:因为一些本地平台只为标准输入和输出流提供有限的缓冲区大小,因此无法及时写入输入流或读取子进程的输出流可能导致子进程阻塞甚至死锁。 * @author jinsx * @date 2019/8/30 10:56 */ public class StreamOutput extends Thread { InputStream is; String type; StreamOutput(InputStream is, String type) { this.is = is; this.type = type; } public void run() { InputStreamReader isr = null; BufferedReader br = null; try { isr = new InputStreamReader(is, "GBK"); br = new BufferedReader(isr); String line = null; while ((line = br.readLine()) != null) { System.out.println(type + ">" + line); } } catch (IOException ioe) { ioe.printStackTrace(); } finally { if(br != null) { try { br.close(); } catch (IOException e) { e.printStackTrace(); } } if(isr != null) { try { isr.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
执行测试结果:
[root@centos_1 book2]# javac -d . AuxiliaryClass.java [root@centos_1 book2]# javac -d . StreamOutput.java [root@centos_1 book2]# javac -d . BusinessClass.java [root@centos_1 book2]# java com.example.demo.runtme.BusinessClass OUTPUT>AuxiliaryClass parameter is : OUTPUT>'Hello OUTPUT>World' ExitValue: 0 [root@centos_1 book2]#
在Java中执行linux命令 Runtime的exec方法
最新推荐文章于 2024-07-30 03:32:07 发布