`

如何在Java中执行其它程序

阅读更多

在编写Java程序时,有时候需要在Java程序中执行另外一个程序。

  1、启动程序Java提供了两种方法用来启动其它程序:

  (1)使用Runtime的exec()方法

  (2)使用ProcessBuilder的start()方法

  不管在哪种操作系统下,程序具有基本类似的一些属性。一个程序启动后就程序操作系统的一个进程,进程在执行的时候有自己的环境变量、有自己的工作目录。Runtime和ProcessBuilder提供了不同的方式来启动程序,设置启动参数、环境变量和工作目录。

  能够在Java中执行的外部程序,必须是一个实际存在的可执行文件,对于shell下的内嵌命令是不能直接执行的。

  采用Runtime的exec执行程序时,首先要使用Runtime的静态方法得到一个Runtime,然后调用Runtime的exec方 法。可以将要执行的外部程序和启动参数、环境变量、工作目录作为参数传递给exec方法,该方法执行后返回一个Process代表所执行的程序。

  Runtime有六个exec方法,其中两个的定义为:

  public Process exec(String[] cmdarray, String[] envp, File dir)

  public Process exec(String command, String[] envp, File dir)

  cmdarray和command为要执行的命令,可以将命令和参数作为一个字符串command传递给exec()方法,也可以将命令和参数一个一个的方在数组cmdarray里传递给exec()方法。

  envp为环境变量,以name=value的形式放在数组中。dir为工作目录。

  可以不要dir参数,或者不要envp和dir参数,这样就多出了其它4个exec()方法。如果没有dir参数或者为null,那么新启动的 进程就继承当前java进程的工作目录。如果没有envp参数或者为null,那么新启动的进程就继承当前java进程的环境变量。

  也可以使用ProcessBuilder类启动一个新的程序,该类是后来添加到JDK中的,而且被推荐使用。通过构造函数设置要执行的命令以及 参数,或者也可以通过command()方法获取命令信息后在进行设置。通过directory(File directory)方法设置工作目录,通过environment()获取环境变量信息来修改环境变量。

  在使用ProcessBuilder构造函数创建一个新实例,设置环境变量、工作目录后,可以通过start()方法来启动新程序,与Runtime的exec()方法一样,该方法返回一个Process对象代表启动的程序。

  ProcessBuilder与Runtime.exec()方法的不同在于ProcessBuilder提供了 redirectErrorStream(boolean redirectErrorStream)方法,该方法用来将进程的错误输出重定向到标准输出里。即可以将错误输出都将与标准输出合并。

  2、Process

  不管通过那种方法启动进程后,都会返回一个Process类的实例代表启动的进程,该实例可用来控制进程并获得相关信息。Process 类提供了执行从进程输入、执行输出到进程、等待进程完成、检查进程的退出状态以及销毁(杀掉)进程的方法:

  (1) void destroy()

  杀掉子进程。

  一般情况下,该方法并不能杀掉已经启动的进程,不用为好。

  (2) int exitValue()

  返回子进程的出口值。

  只有启动的进程执行完成、或者由于异常退出后,exitValue()方法才会有正常的返回值,否则抛出异常。

  (3)InputStream getErrorStream()

  获取子进程的错误流。

  如果错误输出被重定向,则不能从该流中读取错误输出。

  (4)InputStream getInputStream()

  获取子进程的输入流。

  可以从该流中读取进程的标准输出。

  (5)OutputStream getOutputStream()

  获取子进程的输出流。

  写入到该流中的数据作为进程的标准输入。

  (6) int waitFor()

  导致当前线程等待,如有必要,一直要等到由该 Process 对象表示的进程已经终止。

  通过该类提供的方法,可以实现与启动的进程之间通信,达到交互的目的。

  3、从标准输出和错误输出流读取信息

  从启动其他程序的Java进程看,已启动的其他程序输出就是一个普通的输入流,可以通过getInputStream()和getErrorStream来获取。

  对于一般输出文本的进程来说,可以将InputStream封装成BufferedReader,然后就可以一行一行的对进程的标准输出进行处理。

  4、举例

  (1)Runtime.exec()

  import java.io.BufferedReader;

  import java.io.File;

  import java.io.InputStreamReader;

  public class Test1 {

  public static void main(String[] args) {

  try {

  Process p = null;

  String line = null;

  BufferedReader stdout = null;

  //list the files and directorys under C:\

  p = Runtime.getRuntime().exec("CMD.exe /C dir", null, new File("C:\\"));

  stdout = new BufferedReader(new InputStreamReader(p

  .getInputStream()));

  while ((line = stdout.readLine()) != null) {

  System.out.println(line);

  }

  stdout.close();

  //echo the value of NAME

  p = Runtime.getRuntime().exec("CMD.exe /C echo %NAME%", new String[] {"NAME=TEST"});

  stdout = new BufferedReader(new InputStreamReader(p

  .getInputStream()));

  while ((line = stdout.readLine()) != null) {

  System.out.println(line);

  }

  stdout.close();

  } catch (Exception e) {

  e.printStackTrace();

  }

  }

  }

  (2)ProcessBuilder

  import java.io.BufferedReader;import java.io.File;import java.io.InputStreamReader;import java.util.ArrayList;import java.util.List;public class Test2 {public static void main(String[] args) {try {List list = new ArrayList();ProcessBuilder pb = null;Process p = null;String line = null;BufferedReader stdout = null;//list the files and directorys under C:\list.add("CMD.EXE");list.add("/C");list.add("dir");pb = new ProcessBuilder(list);pb.directory(new File("C:\\"));p = pb.start();stdout = new BufferedReader(new InputStreamReader(p.getInputStream()));while ((line = stdout.readLine()) != null) {System.out.println(line);}stdout.close();//echo the value of NAMEpb = new ProcessBuilder();pb.command(new String[] {"CMD.exe", "/C", "echo %NAME%"});pb.environment().put("NAME", "TEST");p = pb.start();stdout = new BufferedReader(new InputStreamReader(p.getInputStream()));while ((line = stdout.readLine()) != null) {System.out.println(line);}stdout.close();} catch (Exception e) {e.printStackTrace();}}}

 

 5、获取进程的返回值

  通常,一个程序/进程在执行结束后会向操作系统返回一个整数值,0一般代表执行成功,非0表示执行出现问题。有两种方式可以用来获取进程的返回 值。一是利用waitFor(),该方法是阻塞的,执导进程执行完成后再返回。该方法返回一个代表进程返回值的整数值。另一个方法是调用 exitValue()方法,该方法是非阻塞的,调用立即返回。但是如果进程没有执行完成,则抛出异常。

  6、阻塞的问题

  由Process代表的进程在某些平台上有时候并不能很好的工作,特别是在对代表进程的标准输入流、输出流和错误输出进行操作时,如果使用不慎,有可能导致进程阻塞,甚至死锁。

  如果将以上事例中的从标准输出重读取信息的语句修改为从错误输出流中读取:

  stdout = new BufferedReader(new InputStreamReader(p.getErrorStream()));

  那么程序将发生阻塞,不能执行完成,而是hang在那里。

  当进程启动后,就会打开标准输出流和错误输出流准备输出,当进程结束时,就会关闭他们。在以上例子中,错误输出流没有数据要输出,标准输出流中 有数据输出。由于标准输出流中的数据没有被读取,进程就不会结束,错误输出流也就不会被关闭,因此在调用readLine()方法时,整个程序就会被阻 塞。为了解决这个问题,可以根据输出的实际先后,先读取标准输出流,然后读取错误输出流。

  但是,很多时候不能很明确的知道输出的先后,特别是要操作标准输入的时候,情况就会更为复杂。这时候可以采用线程来对标准输出、错误输出和标准输入进行分别处理,根据他们之间在业务逻辑上的关系决定读取那个流或者写入数据。

  针对标准输出流和错误输出流所造成的问题,可以使用ProcessBuilder的redirectErrorStream()方法将他们合二为一,这时候只要读取标准输出的数据就可以了。

  当在程序中使用Process的waitFor()方法时,特别是在读取之前调用waitFor()方法时,也有可能造成阻塞。可以用线程的方法来解决这个问题,也可以在读取数据后,调用waitFor()方法等待程序结束。

  总之,解决阻塞的方法应该有两种:

  (1)使用ProcessBuilder类,利用redirectErrorStream方法将标准输出流和错误输出流合二为一,在用start()方法启动进程后,先从标准输出中读取数据,然后调用waitFor()方法等待进程结束。

  如:

  import java.io.BufferedReader;import java.io.File;import java.io.InputStreamReader;import java.util.ArrayList;import java.util.List;public class Test3 {public static void main(String[] args) {try {List list = new ArrayList();ProcessBuilder pb = null;Process p = null;String line = null;BufferedReader stdout = null;//list the files and directorys under C:\list.add("CMD.EXE");list.add("/C");list.add("dir");pb = new ProcessBuilder(list);pb.directory(new File("C:\\"));//merge the error output with the standard outputpb.redirectErrorStream(true);p = pb.start();//read the standard outputstdout = new BufferedReader(new InputStreamReader(p.getInputStream()));while ((line = stdout.readLine()) != null) {System.out.println(line);}int ret = p.waitFor();System.out.println("the return code is " + ret);stdout.close();} catch (Exception e) {e.printStackTrace();}}}

  (2)使用线程

  import java.util.*;import java.io.*;class StreamWatch extends Thread {InputStream is;String type;List output = new ArrayList();boolean debug = false;StreamWatch(InputStream is, String type) {this(is, type, false);}StreamWatch(InputStream is, String type, boolean debug) {this.is = is;this.type = type;this.debug = debug;}public void run() {try {PrintWriter pw = null;InputStreamReader isr = new InputStreamReader(is);BufferedReader br = new BufferedReader(isr);String line = null;while ((line = br.readLine()) != null) {output.add(line);if (debug)System.out.println(type + ">" + line);}if (pw != null)pw.flush();} catch (IOException ioe) {ioe.printStackTrace();}}public List getOutput() {return output;}}public class Test5 {public static void main(String args[]) {try {List list = new ArrayList();ProcessBuilder pb = null;Process p = null;// list the files and directorys under C:\list.add("CMD.EXE");list.add("/C");list.add("dir");pb = new ProcessBuilder(list);pb.directory(new File("C:\\"));p = pb.start();// process error and output messageStreamWatch errorWatch = new StreamWatch(p.getErrorStream(),"ERROR");StreamWatch outputWatch = new StreamWatch(p.getInputStream(),"OUTPUT");// start to watcherrorWatch.start();outputWatch.start();//wait for exitint exitVal = p.waitFor();//print the content from ERROR and OUTPUTSystem.out.println("ERROR: " + errorWatch.getOutput());System.out.println("OUTPUT: " + outputWatch.getOutput());System.out.println("the return code is " + exitVal);} catch (Throwable t) {t.printStackTrace();}}}

  7、在Java中执行Java程序

  执行一个Java程序的关键在于:

  (1)知道JAVA虚拟机的位置,即java.exe或者java的路径

  (2)知道要执行的java程序的位置

  (3)知道该程序所依赖的其他类的位置

(1)待执行的Java类

  public class MyTest {

  public static void main(String[] args) {

  System.out.println("OUTPUT one");

  System.out.println("OUTPUT two");

  System.err.println("ERROR 1");

  System.err.println("ERROR 2");

  for(int i = 0; i < args.length; i++)

  {

  System.out.printf("args[%d] = %s.", i, args[i]);

  }

  }

  }

  (2)执行该类的程序

  import java.util.*;

  import java.io.*;

  class StreamWatch extends Thread {

  InputStream is;

  String type;

  List output = new ArrayList();

  boolean debug = false;

  StreamWatch(InputStream is, String type) {

  this(is, type, false);

  }

  StreamWatch(InputStream is, String type, boolean debug) {

  this.is = is;

  this.type = type;

  this.debug = debug;

  }

  public void run() {

  try {

  PrintWriter pw = null;

  InputStreamReader isr = new InputStreamReader(is);

  BufferedReader br = new BufferedReader(isr);

  String line = null;

  while ((line = br.readLine()) != null) {

  output.add(line);

  if (debug)

  System.out.println(type + ">" + line);

  }

  if (pw != null)

  pw.flush();

  } catch (IOException ioe) {

  ioe.printStackTrace();

  }

  }

  public List getOutput() {

  return output;

  }

  }

  public class Test6 {

  public static void main(String args[]) {

  try {

  List list = new ArrayList();

  ProcessBuilder pb = null;

  Process p = null;

  String java = System.getProperty("java.home") + File.separator + "bin" + File.separator + "java";

  String classpath = System.getProperty("java.class.path");

  // list the files and directorys under C:\

  list.add(java);

  list.add("-classpath");

  list.add(classpath);

  list.add(MyTest.class.getName());

  list.add("hello");

  list.add("world");

  list.add("good better best");

  pb = new ProcessBuilder(list);

  p = pb.start();

  System.out.println(pb.command());

  // process error and output message

  StreamWatch errorWatch = new StreamWatch(p.getErrorStream(),

  "ERROR");

  StreamWatch outputWatch = new StreamWatch(p.getInputStream(),

  "OUTPUT");

  // start to watch

  errorWatch.start();

  outputWatch.start();

  //wait for exit

  int exitVal = p.waitFor();

  //print the content from ERROR and OUTPUT

  System.out.println("ERROR: " + errorWatch.getOutput());

  System.out.println("OUTPUT: " + outputWatch.getOutput());

  System.out.println("the return code is " + exitVal);

  } catch (Throwable t) {

  t.printStackTrace();

  }

  }

  }

分享到:
评论

相关推荐

    java中两种方式调用其他.exe可执行程序

    在 Java 中有两种方式可以调用其他.exe 可执行程序,即使用 `Desktop` 类和 `Runtime` 类。 使用 `Desktop` 类调用其他.exe 可执行程序 `Desktop` 类是 Java 的一个辅助类,提供了许多有用的方法,例如打开文件、...

    如何制作Java可执行程序

    在Java编程中,将程序制作成可执行程序主要是为了方便用户直接运行而无需通过命令行。Java的可执行程序通常是指JAR(Java Archive)文件,它包含了一系列的类文件、资源文件以及相关的元数据。以下是三种常见的生成...

    Linux下Java中调用可执行程序

    在Linux环境下,Java程序可以通过Runtime类或者ProcessBuilder类来调用外部的可执行程序。这个过程通常涉及以下几个关键步骤: 1. **获取运行时环境**: 首先,你需要通过`Runtime.getRuntime()`方法创建一个...

    Java项目制作可执行程序与安装程序_java_

    这个Java项目展示了如何使用Exe4j生成Windows平台下的EXE可执行程序,并通过Inno Setup创建安装包,使得用户能够方便地在Windows环境中运行和安装基于JavaFX的桌面应用。这个项目还涉及到JNA(Java Native Access)...

    通过JAVA执行命令行程序

    本文将详细讲解如何通过Java执行命令行程序,以及在处理过程中可能遇到的线程阻塞问题。 首先,我们来看标题提到的"通过JAVA执行命令行程序"。Java提供了Runtime类的exec()方法来执行外部命令。例如,如果你想要在...

    Java程序执行CMD命令代码实现

    Java程序是如何执行CMD命令的,就是需要RunTime、Process类而已。 具体代码在文档中

    Java项目制作可执行程序与安装程序.rar

    Java项目开发过程中,将应用程序转化为可执行程序和安装程序是发布产品的重要步骤。在这个场景中,我们使用了JavaFX作为桌面应用的开发框架,以及JNA(Java Native Access)技术来实现与本地系统资源的交互。为了将...

    java 记录程序执行的时间

    在Java编程中,记录程序执行时间是一个常见的需求,这有助于我们了解代码的性能,优化算法,或者调试程序。本文将详细介绍如何在Java中记录程序执行时间,并提供一个名为`RecordTimes.java`的示例代码。 首先,我们...

    java程序自动重新启动

    在Java编程中,有时我们需要设计一个程序来实现自动重启的功能,比如在系统出现异常或者更新后需要自动恢复服务。在给定的标题"java程序自动重新启动"中,我们可以理解这是一个实现了自动重启逻辑的Java程序。描述...

    linux 通过脚本执行java程序

    在Linux环境中,通过脚本执行Java程序是一种常见的实践,尤其对于服务器端应用或者自动化任务来说。这使得我们能够更方便地管理和控制Java应用程序的启动、停止以及监控。下面将详细介绍如何编写一个简单的bash脚本...

    Java动态编译Java代码,运行在内存中,并执行

    通过java的ToolProvider创建JavaCompile,用来执行class源文件 * 4.创建DiagnosticCollector用来执行获取执行失败的错误结果 * 5.添加动态执行的编译环境 options 是个集合,添加内容,字符集,classpath等 * 6....

    java定时关机小程序

    这个程序在日常生活中或企业环境中非常有用,比如在执行大量计算任务后自动关闭电脑,或者在无人值守时进行系统维护。下面我们将深入探讨如何使用Java编写这样的程序,以及涉及的关键技术和知识点。 首先,要实现...

    java通过线程控制程序执行超时(新)

    在Java编程中,控制程序执行超时是一项重要的任务,特别是在多线程环境下,我们可能需要确保某个任务不会无限制地运行下去,导致资源耗尽。本文将深入探讨如何使用Java的线程机制来实现程序执行的超时控制,同时也会...

    java打包成可执行程序

    Java打包成可执行程序是一个常见的需求,特别是在分发和部署Java应用程序时。本文将详细介绍如何将Java项目打包成jar文件,以及如何进一步利用JSmooth工具将其转换为Windows平台下的exe可执行程序。 首先,我们将...

    用JAVA调用外部程序并截出程序运行结果

    在Java编程中,有时我们需要与操作系统进行交互,执行一些外部程序并获取其运行结果。这通常通过使用Java的`Runtime`类或者`ProcessBuilder`类来实现。本文将详细讲解如何使用Java调用外部程序以及如何捕获并处理...

    java 桌面程序打包jar可执行包,类似达成exe可执行程序

    这个插件的主要作用是帮助开发者将所有依赖的库文件(如JARs)和主程序一起打包成一个单一的JAR文件,这样用户只需双击该JAR,就能在拥有Java运行环境的机器上运行程序,类似于Windows的.exe可执行程序。 FATJAR...

    java定时执行sql语句

    使用jfinal编写的本地应用,压缩文件里包括了eclipse本程序的源代码和可执行的jar文件。 通过配置数据库连接信息和要执行的sql语句,可实现定时执行多个sql语句。 所要执行的语句只能是写死的,可支持sqlserver ...

    JAVA程序设计.pdf

    JAVA Application是指独立的JAVA程序,可以运行在命令行或图形用户界面中。JAVA Applet是指嵌入到Web页面中的小程序,可以在浏览器中运行。本资源提供了一个简单的JAVA Application和JAVA Applet的示例代码,演示了...

    用bat运行java文件中引用了外部jar的java程序

    在IT行业中,我们经常需要处理各种编程任务,其中之一就是在命令行环境下运行包含外部jar依赖的Java程序。在Windows操作系统中,我们通常会使用批处理(BAT)文件来自动化这一过程。下面将详细介绍如何通过BAT文件...

    java用bat运行程序

    在IT行业中,尤其是在Windows操作系统环境下,我们经常需要执行一些Java程序。为了方便快捷地运行这些程序,我们可以将它们封装到批处理(.bat)文件中。这样,只需双击.bat文件,就可以自动调用Java虚拟机(JVM)...

Global site tag (gtag.js) - Google Analytics