java的Runtime的exec

参看: http://berdy.iteye.com/blog/810223

Runtime 封装着java程序的运行时环境。通过Runtime实例,java应用能够与其运行的环境连接。Runtime在jvm中保持一个单例,所以不能通过Runtime类的构造函数。只能通过Runtime.getRuntime()来获的当前Runtime的一个实例。获得Runtime实例后,就可以通过Runtime的exec()方法在当前jvm进程外启动其他进程了。很常见的一个应用就是,启动浏览器进程来显示一个程序的帮助页面。

在Runtime类中存在四个exec()重载方法.

Java代码  

  1. public Process exec(String command);
  2. public Process exec(String [] cmdArray);
  3. public Process exec(String command, String [] envp);
  4. public Process exec(String [] cmdArray, String [] envp);

主要参数是要启动进程的名称,以及启动该进程时需要的参数。然后是一些环境相关的属性。envp是已name=value,

形式传入的。具体查看下源码便一目了然了。

通常,启动另外一个进程后,需要获取另外一个进程的执行结果,然后根据结果执行后续的流程。要获取外部进程的运行结果,可以调用Process的exitValue() 方法。下面代码中启动一个java编译器进程。

Java代码  

  1. try {
  2. Runtime rt = Runtime.getRuntime();
  3. Process proc = rt.exec("javac");
  4. int exitVal = proc.exitValue();
  5. System.out.println("Process exitValue: " + exitVal);
  6. } catch (Throwable t) {
  7. t.printStackTrace();
  8. }

不幸的是,你将看到下面的结果:

java.lang.IllegalThreadStateException: process has not exited

at java.lang.ProcessImpl.exitValue(Native Method)

at com.test.runtime.Test.BadExecJavac(Test.java:13)

at com.test.runtime.Test.main(Test.java:5)

原因是exitValue()方法并不会等待外部进程结束。如果外部进程还未结束,exitValue()将会抛出IllegalThreadStateException。解决办法就是调用Process的waitfor()方法。waitfor()方法会挂起当前线程,一直等到外部进程结束。当然使用exitValue()或者waitfor()完全取决你的需求。可以设个boolean标志,来确定使用哪个。运行下面的代码:

Java代码  

  1. try {
  2. Runtime rt = Runtime.getRuntime();
  3. Process proc = rt.exec("javac");
  4. int exitVal = proc.waitFor();
  5. System.out.println("Process exitValue: " + exitVal);
  6. } catch (Throwable t) {
  7. t.printStackTrace();
  8. }

发现程序被阻塞了,什么原因呢?JDK‘s Javadoc文档解释说:

Because some native platforms only provide limited buffer size for standard input and output streams, failure to promptly write the input stream or read the output stream of the subprocess may cause the subprocess to block, and even deadlock.

翻译:

一些平台只为标准输入输出提供有限的缓存。错误的写子进程的输入流或者错误的都子进程的输出流都有可能造成子进程的阻塞,甚至是死锁。

解决上面问题的办法就是程序中将子进程的输出流和错误流都输出到标准输出中。

Java代码  

  1. try {
  2. Runtime rt = Runtime.getRuntime();
  3. Process proc = rt.exec("javac");
  4. InputStream stderr = proc.getErrorStream();
  5. InputStreamReader isr = new InputStreamReader(stderr);
  6. BufferedReader br = new BufferedReader(isr);
  7. String line = null;
  8. System.out.println("<ERROR>");
  9. while ((line = br.readLine()) != null)
  10. System.out.println(line);
  11. System.out.println("</ERROR>");
  12. int exitVal = proc.waitFor();
  13. System.out.println("Process exitValue: " + exitVal);
  14. } catch (Throwable t) {
  15. t.printStackTrace();
  16. }

上面的代码中仅仅是输出了错误流,并没有输出子进程的输出流。在程序中最好是能将子进程的错误流和输出流都能输出并清空。

在windows系统中,很多人会利用Runtime.exec()来调用不可执行的命令。例如dir和copy;

Java代码  

  1. try {
  2. Runtime rt = Runtime.getRuntime();
  3. Process proc = rt.exec("dir");
  4. InputStream stdin = proc.getInputStream();
  5. InputStreamReader isr = new InputStreamReader(stdin);
  6. BufferedReader br = new BufferedReader(isr);
  7. String line = null;
  8. System.out.println("<OUTPUT>");
  9. while ((line = br.readLine()) != null)
  10. System.out.println(line);
  11. System.out.println("</OUTPUT>");
  12. int exitVal = proc.waitFor();
  13. System.out.println("Process exitValue: " + exitVal);
  14. } catch (Throwable t) {
  15. t.printStackTrace();
  16. }

运行上面的代码,将会得到一个错误代码为2的错误。在win32系统中,error=2表示文件未找到。也就是不存在dir.exe和copy.exe。这是因为dir命令式windows中命令行解析器的一部分,并不是单独的一个可执行的命令。要运行上面的命令,得先启动windows下的命令行解析器command.com或者cmd.exe,这个取决于windows的系统的版本。

Java代码  

  1. import java.io.BufferedReader;
  2. import java.io.IOException;
  3. import java.io.InputStream;
  4. import java.io.InputStreamReader;
  5. class StreamGobbler extends Thread {
  6. InputStream is;
  7. String type;
  8. StreamGobbler(InputStream is, String type) {
  9. this.is = is;
  10. this.type = type;
  11. }
  12. public void run() {
  13. try {
  14. InputStreamReader isr = new InputStreamReader(is);
  15. BufferedReader br = new BufferedReader(isr);
  16. String line = null;
  17. while ((line = br.readLine()) != null)
  18. System.out.println(type + ">" + line);
  19. } catch (IOException ioe) {
  20. ioe.printStackTrace();
  21. }
  22. }
  23. }
  24. public class GoodWindowsExec {
  25. public static void main(String args[]) {
  26. if (args.length < 1) {
  27. System.out.println("USAGE: java GoodWindowsExec <cmd>");
  28. System.exit(1);
  29. }
  30. try {
  31. String osName = System.getProperty("os.name");
  32. String[] cmd = new String[3];
  33. if (osName.equals("Windows NT")) {
  34. cmd[0] = "cmd.exe";
  35. cmd[1] = "/C";
  36. cmd[2] = args[0];
  37. } else if (osName.equals("Windows 95")) {
  38. cmd[0] = "command.com";
  39. cmd[1] = "/C";
  40. cmd[2] = args[0];
  41. }
  42. Runtime rt = Runtime.getRuntime();
  43. System.out.println("Execing " + cmd[0] + " " + cmd[1] + " " + cmd[2]);
  44. Process proc = rt.exec(cmd);
  45. StreamGobbler errorGobbler = new StreamGobbler(proc.getErrorStream(), "ERROR");
  46. StreamGobbler outputGobbler = new StreamGobbler(proc.getInputStream(), "OUTPUT");
  47. errorGobbler.start();
  48. outputGobbler.start();
  49. int exitVal = proc.waitFor();
  50. System.out.println("ExitValue: " + exitVal);
  51. } catch (Throwable t) {
  52. t.printStackTrace();
  53. }
  54. }
  55. }

另外,Runtime.exec()并不是命令解析器,这是启动某个进程。并不能执行一些命令行的命令。下面是一个常见的错误:

Java代码  

  1. try {
  2. Runtime rt = Runtime.getRuntime();
  3. Process proc = rt.exec("java jecho ‘Hello World‘ > test.txt");
  4. StreamGobbler errorGobbler = new StreamGobbler(proc.getErrorStream(), "ERROR");
  5. StreamGobbler outputGobbler = new StreamGobbler(proc.getInputStream(), "OUTPUT");
  6. errorGobbler.start();
  7. outputGobbler.start();
  8. int exitVal = proc.waitFor();
  9. System.out.println("ExitValue: " + exitVal);
  10. } catch (Throwable t) {
  11. t.printStackTrace();
  12. }

上面的代码希望像DOS系统中一样将命令的执行结果输出到文件中去。但是Runtime.exec()并不是命令行解析器。要想重定向输出流,必须在程序中编码实现。

Java代码  

  1. import java.util.*;
  2. import java.io.*;
  3. class StreamGobbler extends Thread {
  4. InputStream is;
  5. String type;
  6. OutputStream os;
  7. StreamGobbler(InputStream is, String type) {
  8. this(is, type, null);
  9. }
  10. StreamGobbler(InputStream is, String type, OutputStream redirect) {
  11. this.is = is;
  12. this.type = type;
  13. this.os = redirect;
  14. }
  15. public void run() {
  16. try {
  17. PrintWriter pw = null;
  18. if (os != null)
  19. pw = new PrintWriter(os);
  20. InputStreamReader isr = new InputStreamReader(is);
  21. BufferedReader br = new BufferedReader(isr);
  22. String line = null;
  23. while ((line = br.readLine()) != null) {
  24. if (pw != null)
  25. pw.println(line);
  26. System.out.println(type + ">" + line);
  27. }
  28. if (pw != null)
  29. pw.flush();
  30. } catch (IOException ioe) {
  31. ioe.printStackTrace();
  32. }
  33. }
  34. }
  35. public class GoodWinRedirect {
  36. public static void main(String args[]) {
  37. if (args.length < 1) {
  38. System.out.println("USAGE java GoodWinRedirect <outputfile>");
  39. System.exit(1);
  40. }
  41. try {
  42. FileOutputStream fos = new FileOutputStream(args[0]);
  43. Runtime rt = Runtime.getRuntime();
  44. Process proc = rt.exec("java jecho ‘Hello World‘");
  45. StreamGobbler errorGobbler = new StreamGobbler(proc.getErrorStream(), "ERROR");
  46. StreamGobbler outputGobbler = new StreamGobbler(proc.getInputStream(), "OUTPUT", fos);
  47. errorGobbler.start();
  48. outputGobbler.start();
  49. int exitVal = proc.waitFor();
  50. System.out.println("ExitValue: " + exitVal);
  51. fos.flush();
  52. fos.close();
  53. } catch (Throwable t) {
  54. t.printStackTrace();
  55. }
  56. }
  57. }

实例

package com.yiibai;

public class RuntimeDemo {

   public static void main(String[] args) {
      try {
         // print a message
         System.out.println("Executing notepad.exe");
         // create a process and execute notepad.exe
         Process process = Runtime.getRuntime().exec("notepad.exe");
         // print another message
         System.out.println("Notepad should now open.");
      } catch (Exception ex) {
         ex.printStackTrace();
      }

   }
}
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;      

public class JavaExeBat
{
    public static void main(String[] args)
     {
         Process p;
        //test.bat中的命令是ipconfig/all
         String cmd="c:\\test\\test.bat";      

        try
         {
            //执行命令
             p = Runtime.getRuntime().exec(cmd);
            //取得命令结果的输出流
             InputStream fis=p.getInputStream();
            //用一个读输出流类去读
             InputStreamReader isr=new InputStreamReader(fis);
            //用缓冲器读行
             BufferedReader br=new BufferedReader(isr);
             String line=null;
            //直到读完为止
            while((line=br.readLine())!=null)
             {
                 System.out.println(line);
             }
         }
        catch (IOException e)
         {
             e.printStackTrace();
         }
     }
} 

心得

1.不要试图对exec()执行的程序异步取得返回参数;

2.及时得处理程序的输入和输出(即使你不用这些数据),否则会出现难以预料的后果;

3.不要把exec()当作一个shell的命令行,exec()只能执行一个程序。有个比较好的解决方案,在linux里可以利用sh -c命令来模拟一个命令行,在windows中则是cmd /c。

时间: 2024-10-24 16:20:58

java的Runtime的exec的相关文章

java中Runtime.getRuntime().exec()的坑,会造成阻塞的解决

synchronized (this) { process = Runtime.getRuntime().exec(cmds); } //记录进程缓存错误信息 final StringBuffer errorLog = new StringBuffer(); //获取执行进程的错误流 final InputStream errorStream = process.getErrorStream(); final InputStream inputStream = process.getInputS

Java Runtime.getRuntime().exec 执行带空格命令解决办法

String command = OpenOffice_HOME + "program\\soffice -headless -accept=\"socket,host=127.0.0.1,port=8100;urp;\" -nofirststartwizard "; command = "cmd /c start "+command.replaceAll(" ","\" \""); P

JAVA中Runtime类以及exec()方法,Process的使用

package ioTest.io1; /* * Runtime:每个 Java 应用程序都有一个 Runtime 类实例,使应用程序能够与其运行的环境相连接. * 这也是jvm实现跨平台的一个重要原因. * 可以通过 getRuntime 方法获取当前运行时. * API分析: * public class Runtime extends Object * 每个 Java 应用程序都有一个 Runtime 类实例,使应用程序能够与其运行的环境相连接. * 可以通过 getRuntime 方法获

[转]Java中Runtime.exec的一些事

0 预备知识 1 不正确的调用exitValue 2不正确的调用waitFor 3 一种可接受的调用方式 4 调用认为是可执行程序的时候容易发生的错误 5 window执行的良好示例 6 不良好的重定向命令输出 7 良好的重定向输出示例 8 总结 9 问答 0 预备知识 Runtime类是一个与JVM运行时环境有关的Singleton类,有以下几个值得注意的地方: 0.1 Runtime.getRuntime()可以取得当前JVM的运行时环境,这也是在Java中唯一得到运行时环境的方法. 0.2

使用Runtime.getRuntime().exec()在java中调用python脚本

举例有一个Python脚本叫test.py,现在想要在Java里调用这个脚本.假定这个test.py里面使用了拓展的包,使得pythoninterpreter之类内嵌的编译器无法使用,那么只能采用java调用控制台进程,即 Runtime.getRuntime().exec(),来运行这个python脚本. 在windows下运行这个程序,假如是参考了一些百度来的被转载了无数遍的文章,很有可能运行结果是根本没有执行这个脚本.经过测试,在java中执行如下代码可以成功运行test.py文件: --

Runtime.getRuntime.exec()执行linux脚本导致程序卡死有关问题

Runtime.getRuntime.exec()执行linux脚本导致程序卡死问题问题: 在Java程序中,通过Runtime.getRuntime().exec()执行一个Linux脚本导致程序被挂住,而在终端上直接执行这个脚本则没有任何问题.原因: 先来看Java代码: public final static void process1(String[] cmdarray) {        Process p = null;        BufferedReader br = null

深入研究java.lang.Runtime类

深入研究java.lang.Runtime类 一.概述      Runtime类封装了运行时的环境.每个 Java 应用程序都有一个 Runtime 类实例,使应用程序能够与其运行的环境相连接.      一般不能实例化一个Runtime对象,应用程序也不能创建自己的 Runtime 类实例,但可以通过 getRuntime 方法获取当前Runtime运行时对象的引用.      一旦得到了一个当前的Runtime对象的引用,就可以调用Runtime对象的方法去控制Java虚拟机的状态和行为.

浅析Java.lang.Runtime类

一.概述      Runtime类封装了运行时的环境.每个 Java 应用程序都有一个 Runtime 类实例,使应用程序能够与其运行的环境相连接.      一般不能实例化一个Runtime对象,应用程序也不能创建自己的 Runtime 类实例,但可以通过 getRuntime 方法获取当前Runtime运行时对象的引用.      一旦得到了一个当前的Runtime对象的引用,就可以调用Runtime对象的方法去控制Java虚拟机的状态和行为.       当Applet和其他不被信任的代

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

场景:linux下,在web工程里调用一个C++程序,实现代码如下: StringBuffer cmd = new StringBuffer();cmd.append("nohup "); ……System.out.println("执行程序命令:"+cmd.toString());String[] cmds = { "/bin/sh", "-c", cmd.toString()};Runtime.getRuntime().e