日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

※※Java调用Runtime.exec()要注意的问题

發(fā)布時間:2023/12/2 java 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ※※Java调用Runtime.exec()要注意的问题 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
※※Java調(diào)用Runtime.exec()要注意的問題 標簽:execJavaRuntime 字體:【默認中大】
http://it.superkoo.com/#/topic/479/

最近開發(fā)一個項目需要在JAVA中調(diào)用VC寫的一個EXE程序,首先想到的方法肯定是用Runtime.exec(),但一寫就發(fā)現(xiàn),事情并沒有那么的簡單。后來經(jīng)過多番調(diào)試與查找資料才明白了其中的細節(jié):

(1)等待命令執(zhí)行結(jié)束用waitFor(),其返回值就是命令的返回值
(2)如果出現(xiàn)程序執(zhí)行被掛起,沒有任何反應(yīng)的情況,是由于沒有讀取命令子進程的正常輸出流或錯誤輸出流導(dǎo)致緩沖區(qū)被占滿,進程被鎖住。這個時候需要把輸出流中的內(nèi)容給讀出來。最好的做法是使用兩個線程,分別同時讀取正常輸出流和錯誤輸出流。
(3)執(zhí)行Windows平臺上的命令時使用cmd.exe /C,如cmd.exe /C dir。
(4)記得關(guān)閉命令子進程的輸入流,通過Process.getOutputStream().close(),這樣不會導(dǎo)致命令子進程被鎖住。

1、Runtime.exec的用法

The class java.lang.Runtime features a static method called getRuntime(), which retrieves the current Java Runtime Environment. This is the only way to obtain a reference to the Runtime Object. With this reference you can run external programs by invoking the Runtime class’s exec() method. Developers often call this method to launch a browser for displaying a help page in HTML.

There are four overloaded version of the exec() command:

Public Process exec(String command);

Public Process exec(String[] cmdArray);

Public Process exec(String command, String []envp);

Public Process exec(String [] cmdArray, String []envp);

For each of these methods, a command—and possible and possibly a set of arguments—is passed to an operating system function call. This subsequently creates an operating system specific process(a running program )with a reference to a Process class returned to the Java VM. The Process is a abstract class ,because a specific subclass of Process exists for each operating system.

You can pass three possible input params into to these methods:

1.a single string that represents both the program to execute and any args to the program.

2.an array of strings that separate the program from its argumen

3.an array of the environment variables.

Pass the environment variables in the form name=value. If you use the version of exec() with a sigle string for both the program and its arguments, note that the string is parsed using white space as the delimiter via the StringTokenizer class.

The first pitfall relating to Runtime.exec() is the IllegalThreadStateException the prevalent first test of an API is to code its most obvious methods.To see the value the external process returns we use the exitValue() method on the Process class. In our first example, we will attempt to execute the Java compliere(javac.exe)

2、一個錯誤的程序示例

java 代碼
  • import java.util.*;
  • import java.io.*;
  • public class BadExecJavac
  • {
  • ? ? public static void main(String args[])
  • ? ? {
  • ? ? ? ? try
  • ? ? ? ? { ? ? ? ? ??
  • ? ? ? ? ? ? Runtime rt = Runtime.getRuntime();
  • ? ? ? ? ? ? Process proc = rt.exec("javac");
  • ? ? ? ? ? ? int exitVal = proc.exitValue();
  • ? ? ? ? ? ? System.out.println("Process exitValue: " + exitVal);
  • ? ? ? ? } catch (Throwable t)
  • ? ? ? ? ? {
  • ? ? ? ? ? ? t.printStackTrace();
  • ? ? ? ? ? }
  • ? ? }
  • }
  • 運行結(jié)果如下:

    E:\classes\com\javaworld\jpitfalls\article2>java BadExecJavac

    java.lang.IllegalThreadStateException: process has not exited

    ? ? ? ? ?at java.lang.Win32Process.exitValue(Native Method)

    ? ? ? ? ?at BadExecJavac.main(BadExecJavac.java:13)

    這是因為當進程還沒有結(jié)束的情況下,調(diào)用exitValue方法會拋出IllegalThreadStateException.當然了我們會問為什嗎這個方法不會等到進程結(jié)束在返回一個合理的值?

    在檢查Process類的所有可用方法以后我們發(fā)現(xiàn)WairFor()是一個更合適的方法。事實上waitFor也會返回exit value。這意味著你不可以同時用exitvalue和waitfor,而是只能選擇一個。

    當然了也有情況你要在waitfor之前用exitvalue方法:就是你不想因為外部程序永遠無法完成而一直等待下去。

    因此為了避免這個陷阱,我們要么捕獲IllegalThreadStateException異常,要么等待進程完成。我們相當然的以為可以用waitfor來等待程序的結(jié)束。代碼如下:

    java 代碼
  • import java.util.*;
  • import java.io.*;
  • public class BadExecJavac2
  • {
  • ? ? ?public static void main(String args[])
  • ? ? ?{
  • ? ? ? ? ?try
  • ? ? ? ? ?{ ? ? ? ? ? ??
  • ? ? ? ? ? ? Runtime rt = Runtime.getRuntime();
  • ? ? ? ? ? ? ?Process proc = rt.exec("javac");
  • ? ? ? ? ? ? ?int exitVal = proc.waitFor();
  • ? ? ? ? ? ? ?System.out.println("Process exitValue: " + exitVal);
  • ? ? ? ? ?} catch (Throwable t)
  • ? ? ? ? ? ?{
  • ? ? ? ? ? ? ?t.printStackTrace();
  • ? ? ? ? ? ?}
  • ? ? ?}
  • }
  • 這次在linux下面返回的結(jié)果是2,而在windows下面據(jù)說程序會掛起,關(guān)于其原因我們可以在jdk文檔中找到部分解釋:因為一些操作系統(tǒng)為標準的輸入輸出僅僅提供有限的緩沖區(qū),當不能正確的將信息寫進輸入流或者從輸出流中獲取信息時,就會導(dǎo)致子進程的阻塞,甚至死鎖。

    3、一個平庸的解決方案

    現(xiàn)在我們就根據(jù)jdk文檔來處理javac進程的輸出,當你不帶任何參數(shù)運行javac時,它會打印出一系列的有用的提示信息。而這些會被傳送到stderr流中。我們可以寫程序在其返回前獲取這些信息。下面的代碼提供了一個平庸的解決方案。

    java 代碼
  • import java.util.*;
  • import java.io.*;
  • public class MediocreExecJavac
  • {
  • ? ? ?public static void main(String args[])
  • ? ? ?{
  • ? ? ? ? ?try
  • ? ? ? ? ?{ ? ? ? ? ? ??
  • ? ? ? ? ? ? Runtime rt = Runtime.getRuntime();
  • ? ? ? ? ? ? ?Process proc = rt.exec("javac");
  • ? ? ? ? ? ? ?InputStream stderr = proc.getErrorStream();
  • ? ? ? ? ? ? ?InputStreamReader isr = new InputStreamReader(stderr);
  • ? ? ? ? ? ? ?BufferedReader br = new BufferedReader(isr);
  • ? ? ? ? ? ? ?String line = null;
  • ? ? ? ? ? ? ?System.out.println("<ERROR>");
  • ? ? ? ? ? ? ?while ( (line = br.readLine()) != null)
  • ? ? ? ? ? ? ? ? ?System.out.println(line);
  • ? ? ? ? ? ? ?System.out.println("</ERROR>");
  • ? ? ? ? ? ? ?int exitVal = proc.waitFor();
  • ? ? ? ? ? ? ?System.out.println("Process exitValue: " + exitVal);
  • ? ? ? ? ?} catch (Throwable t)
  • ? ? ? ? ? ?{
  • ? ? ? ? ? ? ?t.printStackTrace();
  • ? ? ? ? ? ?}
  • ? ? ?}
  • }
  • 這次程序可以正確的輸出了提示信息,但是我們應(yīng)該注意到其返回代碼是2,我們知道任何非0的返回代碼都表示程序不正常。所以我們需要進一步的查找原因。對于win32而言是file not found,很明顯javac期望我們提供編譯的文件。所以對于永遠掛起的問題,如果你運行的程序會有輸出或者要求輸出入時,你需要處理輸出和輸入。

    3、不要把命令當成一個可以執(zhí)行的程序

    很多新手把一些windows的命令當中可以獨立運行的程序因此他們就陷入了Runtime的另一個陷阱,如下面的例子所示:

    java 代碼
  • import java.util.*;
  • import java.io.*;
  • public class BadExecWinDir
  • {
  • ? ? ?public static void main(String args[])
  • ? ? ?{
  • ? ? ? ? ?try
  • ? ? ? ? ?{ ? ? ? ? ? ??
  • ? ? ? ? ? ? Runtime rt = Runtime.getRuntime();
  • ? ? ? ? ? ? ?Process proc = rt.exec("dir");
  • ? ? ? ? ? ? ?InputStream stdin = proc.getInputStream();
  • ? ? ? ? ? ? ?InputStreamReader isr = new InputStreamReader(stdin);
  • ? ? ? ? ? ? ?BufferedReader br = new BufferedReader(isr);
  • ? ? ? ? ? ? ?String line = null;
  • ? ? ? ? ? ? ?System.out.println("<OUTPUT>");
  • ? ? ? ? ? ? ?while ( (line = br.readLine()) != null)
  • ? ? ? ? ? ? ? ? ?System.out.println(line);
  • ? ? ? ? ? ? ?System.out.println("</OUTPUT>");
  • ? ? ? ? ? ? ?int exitVal = proc.waitFor(); ? ? ? ? ? ??
  • ? ? ? ? ? ? System.out.println("Process exitValue: " + exitVal);
  • ? ? ? ? ?} catch (Throwable t)
  • ? ? ? ? ? ?{
  • ? ? ? ? ? ? ?t.printStackTrace();
  • ? ? ? ? ? ?}
  • ? ? ?}
  • }
  • 據(jù)說在windows下面會拋出如下的異常:

    java.io.IOException: CreateProcess: dir error=2

    ? ? ? ? ?at java.lang.Win32Process.create(Native Method)

    ? ? ? ? ?at java.lang.Win32Process.<init>(Unknown Source)

    ? ? ? ? ?at java.lang.Runtime.execInternal(Native Method)

    ? ? ? ? ?at java.lang.Runtime.exec(Unknown Source)

    ? ? ? ? ?at java.lang.Runtime.exec(Unknown Source)

    ? ? ? ? ?at java.lang.Runtime.exec(Unknown Source)

    ? ? ? ? ?at java.lang.Runtime.exec(Unknown Source)

    ? ? ? ? ?at BadExecWinDir.main(BadExecWinDir.java:12)

    我在linux下面運行的結(jié)果是正確的。前面說了在win32下面2代表是文件沒有找到,而在這種情況下表明是dir.exe沒有找到,(因為根本就沒有這個文件,他們都被封裝到common.com (win95)或者cmd.exe中了。

    下面我們列出一個正確的處理Process的輸入輸出流的方法。需要用一個線程類。

    java 代碼
  • import java.util.*;
  • import java.io.*;
  • class StreamGobbler extends Thread
  • {
  • ? ? ?InputStream is;
  • ? ? ?String type;
  • ? ? StreamGobbler(InputStream is, String type)
  • ? ? ?{
  • ? ? ? ? ?this.is = is;
  • ? ? ? ? ?this.type = type;
  • ? ? ?}
  • ? ? ?
  • ? ? public void run()
  • ? ? ?{
  • ? ? ? ? ?try
  • ? ? ? ? ?{
  • ? ? ? ? ? ? ?InputStreamReader isr = new InputStreamReader(is);
  • ? ? ? ? ? ? ?BufferedReader br = new BufferedReader(isr);
  • ? ? ? ? ? ? ?String line=null;
  • ? ? ? ? ? ? ?while ( (line = br.readLine()) != null)
  • ? ? ? ? ? ? ? ? ?System.out.println(type + ">" + line); ? ??
  • ? ? ? ? ? ? } catch (IOException ioe)
  • ? ? ? ? ? ? ? ?{
  • ? ? ? ? ? ? ? ? ?ioe.printStackTrace(); ?
  • ? ? ? ? ? ? ? }
  • ? ? ?}
  • }
  • 用于專門的處理輸入輸出。

    java 代碼
  • public class GoodWindowsExec
  • {
  • ? ? ?public static void main(String args[])
  • ? ? ?{
  • ? ? ? ? ?if (args.length < 1)
  • ? ? ? ? ?{
  • ? ? ? ? ? ? ?System.out.println("USAGE: java GoodWindowsExec <cmd>");
  • ? ? ? ? ? ? ?System.exit(1);
  • ? ? ? ? ?}
  • ? ? ? ? ?
  • ? ? ? ? try
  • ? ? ? ? ?{ ? ? ? ? ? ??
  • ? ? ? ? ? ? String osName = System.getProperty("os.name" );
  • ? ? ? ? ? ? ?String[] cmd = new String[3];
  • ? ? ? ? ? ? ?if( osName.equals( "Windows NT" ) )
  • ? ? ? ? ? ? ?{
  • ? ? ? ? ? ? ? ? ?cmd[0] = "cmd.exe" ;
  • ? ? ? ? ? ? ? ? ?cmd[1] = "/C" ;
  • ? ? ? ? ? ? ? ? ?cmd[2] = args[0];
  • ? ? ? ? ? ? ?}
  • ? ? ? ? ? ? ?else if( osName.equals( "Windows 95" ) )
  • ? ? ? ? ? ? ?{
  • ? ? ? ? ? ? ? ? ?cmd[0] = "command.com" ;
  • ? ? ? ? ? ? ? ? ?cmd[1] = "/C" ;
  • ? ? ? ? ? ? ? ? ?cmd[2] = args[0];
  • ? ? ? ? ? ? ?}
  • ? ? ? ? ? ? ?
  • ? ? ? ? ? ? Runtime rt = Runtime.getRuntime();
  • ? ? ? ? ? ? ?System.out.println("Execing " + cmd[0] + " " + cmd[1]?
  • ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?+ " " + cmd[2]);
  • ? ? ? ? ? ? ?Process proc = rt.exec(cmd);
  • ? ? ? ? ? ? ?// any error message?
  • ? ? ? ? ? ? ?StreamGobbler errorGobbler = new?
  • ? ? ? ? ? ? ? ? StreamGobbler(proc.getErrorStream(), "ERROR"); ? ? ? ? ? ??
  • ? ? ? ? ? ??
  • ? ? ? ? ? ? // any output?
  • ? ? ? ? ? ? ?StreamGobbler outputGobbler = new?
  • ? ? ? ? ? ? ? ? StreamGobbler(proc.getInputStream(), "OUTPUT");
  • ? ? ? ? ? ? ? ? ?
  • ? ? ? ? ? ? // kick them off
  • ? ? ? ? ? ? ?errorGobbler.start();
  • ? ? ? ? ? ? ?outputGobbler.start();
  • ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
  • ? ? ? ? ? ? // any error???
  • ? ? ? ? ? ? ?int exitVal = proc.waitFor();
  • ? ? ? ? ? ? ?System.out.println("ExitValue: " + exitVal); ? ? ? ??
  • ? ? ? ? } catch (Throwable t)
  • ? ? ? ? ? ?{
  • ? ? ? ? ? ? ?t.printStackTrace();
  • ? ? ? ? ? ?}
  • ? ? ?}
  • }
  • 如果運行如下命令上面的代碼會調(diào)用word程序

    >java GoodWindowExec “abc.doc”

    也就是說文件類型如果window能夠識別它就會調(diào)用對應(yīng)的程序處理。

    StreamGlobbler的最重要作用是他會清空所有的傳遞給他的inputstream,這樣不會造成Process阻塞或者死鎖。

    另外一種實現(xiàn)方式:

    java 代碼
  • package cmd;?
  • ?
  • import java.io.BufferedReader;?
  • import java.io.InputStream;?
  • import java.io.InputStreamReader;?
  • ?
  • class StreamDrainer implements Runnable {?
  • ??? private InputStream ins;?
  • ?
  • ??? public StreamDrainer(InputStream ins) {?
  • ??????? this.ins = ins;?
  • ??? }?
  • ?
  • ??? public void run() {?
  • ??????? try {?
  • ??????????? BufferedReader reader = new BufferedReader(?
  • ??????????????????? new InputStreamReader(ins));?
  • ??????????? String line = null;?
  • ??????????? while ((line = reader.readLine()) != null) {?
  • ??????????????? System.out.println(line);?
  • ??????????? }?
  • ??????? } catch (Exception e) {?
  • ??????????? e.printStackTrace();?
  • ??????? }?
  • ??? }?
  • ?
  • }?
  • ?
  • public class TestRunCmd {?
  • ?
  • ??? public static void main(String[] args) {?
  • ??????? String[] cmd = new String[] { "cmd.exe", "/C", "wmic process get name" };?
  • ??????? try {?
  • ??????????? Process process = Runtime.getRuntime().exec(cmd);?
  • ?????????????
  • ??????????? new Thread(new StreamDrainer(process.getInputStream())).start();?
  • ??????????? new Thread(new StreamDrainer(process.getErrorStream())).start();?
  • ?????????????
  • ??????????? process.getOutputStream().close();?
  • ?
  • ??????????? int exitValue = process.waitFor();?
  • ??????????? System.out.println("返回值:" + exitValue);?
  • ??????? } catch (Exception e) {?
  • ??????????? e.printStackTrace();?
  • ??????? }?
  • ?
  • ??? }?
  • ?
  • }?
  • 4、不要把exec當成命令行,它不會重定向文件

    如你在linux下面type ls> abc.txt或者在window下面dir>abc.txt 會把輸出的結(jié)果通過管道重定向到文件中。但是exec不會。你必須自己寫程序來處理。


    總結(jié)

    以上是生活随笔為你收集整理的※※Java调用Runtime.exec()要注意的问题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。