參考鏈接: Java中的JVM的關閉掛鉤
1? ? ? ? ? ? JDK中Runtime的定義??
?
?
??
?
?
?http://blog.csdn.net/lysnow_oss/archive/2007/05/12/1606349.aspx
??
?
?
?<轉載>
?
?
?那就首先說點Runtime類吧,他是一個與JVM運行時環境有關的類,這個類是Singleton的。我說幾個自己覺得重要的地方。
?
?
?1、Runtime.getRuntime()可以取得當前JVM的運行時環境,這也是在Java中唯一一個得到運行時環境的方法。
?
?
?2、Runtime上其他大部分的方法都是實例方法,也就是說每次進行運行時調用時都要用到getRuntime方法。
?
?
?3、Runtime中的exit方法是退出當前JVM的方法,估計也是唯一的一個吧,因為我看到System類中的exit實際上也是通過調用 Runtime.exit()來退出JVM的,這里說明一下Java對Runtime返回值的一般規則(后邊也提到了),0代表正常退出,非0代表異常中 止,這只是Java的規則,在各個操作系統中總會發生一些小的混淆。
?
?
??
?
?
?4、Runtime.addShutdownHook()方法可以注冊一個hook在JVM執行shutdown的過程中,方法的參數只要是一個初始化過但是沒有執行的Thread實例就可以。(注意,Java中的Thread都是執行過了就不值錢的哦)
?
?
?5、說到addShutdownHook這個方法就要說一下JVM運行環境是在什么情況下shutdown或者abort的。文檔上是這樣寫 的,當最后一個非精靈進程退出或者收到了一個用戶中斷信號、用戶登出、系統shutdown、Runtime的exit方法被調用時JVM會啟動 shutdown的過程,在這個過程開始后,他會并行啟動所有登記的shutdown hook(注意是并行啟動,這就需要線程安全和防止死鎖)。當shutdown過程啟動后,只有通過調用halt方法才能中止shutdown的過程并退 出JVM。
?
?
?那什么時候JVM會abort退出那?首先說明一下,abort退出時JVM就是停止運行但并不一定進行shutdown。這只有JVM在遇到 SIGKILL信號或者windows中止進程的信號、本地方法發生類似于訪問非法地址一類的內部錯誤時會出現。這種情況下并不能保證shutdown hook是否被執行。
?
?
??
?
?
?首先講的是?
?Runtime.exec()?
?方法的所有重載。這里要注意的有一點,就是?
?public Process exec(String [] cmdArray, String [] envp);?
?這個方法中?
?cmdArray?
?是一個執行的命令和參數的字符串數組,數組的第一個元素是要執行的命令往后依次都是命令的參數,?
?envp?
?我個人感覺應該和?
?C?
?中的?
?execve?
?中的環境變量是一樣的,?
?envp?
?中使用的是?
?name=value?
?的方式。?
?
?
??
?
?
?2? ? ? ? ? ? Runtime的構造函數和方法??
?
?
??
?
?
?Runtime是個單例類
?
?
??
?
?
? ??
? ? ?方法摘要
? ? ??
? ??
? ? ? void
? ? ??
? ??
? ? ?addShutdownHook 注冊新的虛擬機來關閉掛鉤。 (
? ? ?Thread? ?hook)?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ? int
? ? ??
? ??
? ? ?availableProcessors 向 Java 虛擬機返回可用處理器的數目。 ()?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ??
? ? ?Process??
? ? ??
? ??
? ? ?exec 在單獨的進程中執行指定的字符串命令。 (
? ? ?String? ?command)?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ??
? ? ?Process??
? ? ??
? ??
? ? ?exec 在單獨的進程中執行指定命令和變量。 (
? ? ?String? [] cmdarray)?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ??
? ? ?Process??
? ? ??
? ??
? ? ?exec 在指定環境的獨立進程中執行指定命令和變量。 (
? ? ?String? [] cmdarray,?
? ? ?String? [] envp)?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ??
? ? ?Process??
? ? ??
? ??
? ? ?exec 在指定環境和工作目錄的獨立進程中執行指定的命令和變量。 (
? ? ?String? [] cmdarray,?
? ? ?String? [] envp,?
? ? ?File? ?dir)?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ??
? ? ?Process??
? ? ??
? ??
? ? ?exec 在指定環境的單獨進程中執行指定的字符串命令。 (
? ? ?String? ?command,?
? ? ?String? [] envp)?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ??
? ? ?Process??
? ? ??
? ??
? ? ?exec 在有指定環境和工作目錄的獨立進程中執行指定的字符串命令。 (
? ? ?String? ?command,?
? ? ?String? [] envp,?
? ? ?File? ?dir)?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ? void
? ? ??
? ??
? ? ?exit 通過啟動虛擬機的關閉序列,終止當前正在運行的 Java 虛擬機。 (int status)?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ? long
? ? ??
? ??
? ? ?freeMemory 返回 Java 虛擬機中的空閑內存量。 ()?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ? void
? ? ??
? ??
? ? ?gc 運行垃圾回收器。 ()?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ??
? ? ?InputStream??
? ? ??
? ??
? ? ?getLocalizedInputStream 已過時。 從 JDK 1.1 開始,將本地編碼字節流轉換為 Unicode 字符流的首選方法是使用 InputStreamReader 和 BufferedReader 類。 (
? ? ?InputStream? ?in)?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ??
? ? ?OutputStream??
? ? ??
? ??
? ? ?getLocalizedOutputStream 已過時。 從 JDK 1.1 開始,將 Unicode 字符流轉換為本地編碼字節流的首選方法是使用 OutputStreamWriter、BufferedWriter 和 PrintWriter 類。 (
? ? ?OutputStream? ?out)?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ?static?
? ? ?Runtime??
? ? ??
? ??
? ? ?getRuntime 返回與當前 Java 應用程序相關的運行時對象。 ()?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ? void
? ? ??
? ??
? ? ?halt 強行終止目前正在運行的 Java 虛擬機。 (int status)?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ? void
? ? ??
? ??
? ? ?load 加載作為動態庫的指定文件名。 (
? ? ?String? ?filename)?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ? void
? ? ??
? ??
? ? ?loadLibrary 加載具有指定庫名的動態庫。 (
? ? ?String? ?libname)?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ? long
? ? ??
? ??
? ? ?maxMemory 返回 Java 虛擬機試圖使用的最大內存量。 ()?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ? boolean
? ? ??
? ??
? ? ?removeShutdownHook 取消注冊某個先前已注冊的虛擬機關閉掛鉤。 (
? ? ?Thread? ?hook)?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ? void
? ? ??
? ??
? ? ?runFinalization 運行掛起 finalization 的所有對象的終止方法。 ()?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ?static void
? ? ??
? ??
? ? ?runFinalizersOnExit 已過時。 此方法本身具有不安全性。它可能對正在使用的對象調用終結方法,而其他線程正在操作這些對象,從而導致不正確的行為或死鎖。 (boolean value)?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ? long
? ? ??
? ??
? ? ?totalMemory 返回 Java 虛擬機中的內存總量。 ()?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ? void
? ? ??
? ??
? ? ?traceInstructions 啟用/禁用指令跟蹤。 (boolean on)?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ? void
? ? ??
? ??
? ? ?traceMethodCalls 啟用/禁用方法調用跟蹤。 (boolean on)?
? ? ? ? ? ? ? ??
? ? ??
?
??
?
?
?3? ? ? ? ? ? Runtime的使用??
?
?
?這個程序用exec調用了一個外部命令之后馬上使用exitValue就對其返回值進行檢查,讓我們看看會出現什么問題。
?
?
??
?
?
?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();
? }
? }
? }
?
?
??
?
?
?A run of BadExecJavac produces:?
?
?
? E:classescomjavaworldjpitfallsarticle2>java BadExecJavac
? java.lang.IllegalThreadStateException: process has not exited
? at java.lang.Win32Process.exitValue(Native Method)
? at BadExecJavac.main(BadExecJavac.java:13)
?
?
??
?
?
?這里看原文就可以了解,這里主要的問題就是錯誤的調用了exitValue來取得外部命令的返回值(呵呵,這個錯誤我也曾經犯過),因為 exitValue這個方法是不阻塞的,程序在調用這個方法時外部命令并沒有返回所以造成了異常的出現,這里是由另外的方法來等待外部命令執行完畢的,就 是waitFor方法,這個方法會一直阻塞直到外部命令執行結束,然后返回外部命令執行的結果,作者在這里一頓批評設計者的思路有問題,呵呵,反正我是無 所謂阿,能用就可以拉。但是作者在這里有一個說明,就是exitValue也是有好多用途的。因為當你在一個Process上調用waitFor方法時, 當前線程是阻塞的,如果外部命令無法執行結束,那么你的線程就會一直阻塞下去,這種意外會影響我們程序的執行。所以在我們不能判斷外部命令什么時候執行完 畢而我們的程序還需要繼續執行的情況下,我們就應該循環的使用exitValue來取得外部命令的返回狀態,并在外部命令返回時作出相應的處理。
?
?
??
?
?
?2、對exitValue處改進了的程序
?
?
?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();
? }
? }
? }
?
?
?不幸的是,這個程序也無法執行完成,它沒有輸出但卻一直懸在那里,這是為什么那?
?
?
? JDK文檔中對此有如此的解釋:因為本地的系統對標準輸入和輸出所提供的緩沖池有效,所以錯誤的對標準輸出快速的寫入和從標準輸入快速的讀入都有可能造成子進程的鎖,甚至死鎖。
?
?
? 文檔引述完了,作者又開始批評了,他說JDK僅僅說明為什么問題會發生,卻并沒有說明這個問題怎么解決,這的確是個問題哈。緊接著作者 說出自己的做法,就是在執行完外部命令后我們要控制好Process的所有輸入和輸出(視情況而定),在這個例子里邊因為調用的是Javac,而他在沒有 參數的情況下會將提示信息輸出到標準出錯,所以在下面的程序中我們要對此進行處理。
?
?
? 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("");
? while ( (line = br.readLine()) != null)
? System.out.println(line);
? System.out.println("");
? int exitVal = proc.waitFor();
? System.out.println("Process exitValue: " + exitVal);
? } catch (Throwable t)
? {
? t.printStackTrace();
? }
? }
? }
?
?
? 程序的運行結果為
?
?
?E:classescomjavaworldjpitfallsarticle2>java MediocreExecJavac
??
? Usage: javac?
?
?
?where includes:
? -g Generate all debugging info
? -g:none Generate no debugging info
? -g:{lines,vars,source} Generate only some debugging info
? -O Optimize; may hinder debugging or enlarge class files
? -nowarn Generate no warnings
? -verbose Output messages about what the compiler is doing
? -deprecation Output source locations where deprecated APIs are used
? -classpath Specify where to find user class files
? -sourcepath Specify where to find input source files
? -bootclasspath Override location of bootstrap class files
? -extdirs Override location of installed extensions
? -d Specify where to place generated class files
? -encoding Specify character encoding used by source files
? -target Generate class files for specific VM version
??
? Process exitValue: 2
?
?
? 哎,不管怎么說還是出來了結果,作者作了一下總結,就是說,為了處理好外部命令大量輸出的情況,你要確保你的程序處理好外部命令所需要的輸入或者輸出。
?
?
? 下一個題目,當我們調用一個我們認為是可執行程序的時候容易發生的錯誤(今天晚上我剛剛犯這個錯誤,沒事做這個練習時候發生的)
?
?
?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("");
? while ( (line = br.readLine()) != null)
? System.out.println(line);
? System.out.println("");
? int exitVal = proc.waitFor();?
? System.out.println("Process exitValue: " + exitVal);
? } catch (Throwable t)
? {
? t.printStackTrace();
? }
? }
? }
?
?
?A run of BadExecWinDir produces:?
?
?
? E:classescomjavaworldjpitfallsarticle2>java BadExecWinDir
? java.io.IOException: CreateProcess: dir error=2
? at java.lang.Win32Process.create(Native Method)
? at java.lang.Win32Process.(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)
?
?
? 說實在的,這個錯誤還真是讓我摸不著頭腦,我覺得在windows中返回2應該是沒有找到這個文件的緣故,可能windows 2000中只有cmd命令,dir命令不是當前環境變量能夠解釋的吧。我也不知道了,慢慢往下看吧。
?
?
?嘿,果然和作者想的一樣,就是因為dir命令是由windows中的解釋器解釋的,直接執行dir時無法找到dir.exe這個命令,所以會出 現文件未找到這個2的錯誤。如果我們要執行這樣的命令,就要先根據操作系統的不同執行不同的解釋程序command.com 或者cmd.exe。
?
?
?作者對上邊的程序進行了修改
?
?
?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();?
? }
? }
? }
?
?
?public class GoodWindowsExec
? {
? public static void main(String args[])
? {
? if (args.length < 1)
? {
? System.out.println("USAGE: java GoodWindowsExec ");
? 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();
? }
? }
? }
?
?
?Running GoodWindowsExec with the dir command generates:?
?
?
? E:classescomjavaworldjpitfallsarticle2>java GoodWindowsExec "dir *.java"
? Execing cmd.exe /C dir *.java
? OUTPUT> Volume in drive E has no label.
? OUTPUT> Volume Serial Number is 5C5F-0CC9
? OUTPUT>
? OUTPUT> Directory of E:classescomjavaworldjpitfallsarticle2
? OUTPUT>
? OUTPUT>10/23/00 09:01p 805 BadExecBrowser.java
? OUTPUT>10/22/00 09:35a 770 BadExecBrowser1.java
? OUTPUT>10/24/00 08:45p 488 BadExecJavac.java
? OUTPUT>10/24/00 08:46p 519 BadExecJavac2.java
? OUTPUT>10/24/00 09:13p 930 BadExecWinDir.java
? OUTPUT>10/22/00 09:21a 2,282 BadURLPost.java
? OUTPUT>10/22/00 09:20a 2,273 BadURLPost1.java
? ... (some output omitted for brevity)
? OUTPUT>10/12/00 09:29p 151 SuperFrame.java
? OUTPUT>10/24/00 09:23p 1,814 TestExec.java
? OUTPUT>10/09/00 05:47p 23,543 TestStringReplace.java
? OUTPUT>10/12/00 08:55p 228 TopLevel.java
? OUTPUT> 22 File(s) 46,661 bytes
? OUTPUT> 19,678,420,992 bytes free
? ExitValue: 0
?
?
?這里作者教了一個windows中很有用的方法,呵呵,至少我是不知道的,就是cmd.exe /C +一個windows中注冊了后綴的文檔名,windows會自動地調用相關的程序來打開這個文檔,我試了一下,的確很好用,但是好像文件路徑中有空格的 話就有點問題,我加上引號也無法解決。
?
?
?這里作者強調了一下,不要假設你執行的程序是可執行的程序,要清楚自己的程序是單獨可執行的還是被解釋的,本章的結束作者會介紹一個命令行工具來幫助我們分析。
?
?
?這里還有一點,就是得到process的輸出的方式是getInputStream,這是因為我們要從Java 程序的角度來看,外部程序的輸出對于Java來說就是輸入,反之亦然。
?
?
? 最后的一個漏洞的地方就是錯誤的認為exec方法會接受所有你在命令行或者Shell中輸入并接受的字符串。這些錯誤主要出現在命令作 為參數的情況下,程序員錯誤的將所有命令行中可以輸入的參數命令加入到exec中(這段翻譯的不好,湊合看吧)。下面的例子中就是一個程序員想重定向一個 命令的輸出。
?
?
? import java.util.*;
? import java.io.*;
?
?
?// StreamGobbler omitted for brevity
?
?
?public class BadWinRedirect
? {
? public static void main(String args[])
? {
? try
? {?
? Runtime rt = Runtime.getRuntime();
? Process proc = rt.exec("java jecho 'Hello World' > test.txt");
? // 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();
? }
? }
? }
?
?
?Running BadWinRedirect produces:?
?
?
? E:classescomjavaworldjpitfallsarticle2>java BadWinRedirect
? OUTPUT>'Hello World' > test.txt
? ExitValue: 0
?
?
?程序員的本意是將Hello World這個輸入重訂向到一個文本文件中,但是這個文件并沒有生成,jecho僅僅是將命令行中的參數輸出到標準輸出中,用戶覺得可以像dos中重定向 一樣將輸出重定向到一個文件中,但這并不能實現,用戶錯誤的將exec認為是一個shell解釋器,但它并不是,如果你想將一個程序的輸出重定向到其他的 程序中,你必須用程序來實現他。可用java.io中的包。
?
?
? import java.util.*;
? import java.io.*;
?
?
?class StreamGobbler extends Thread
? {
? InputStream is;
? String type;
? OutputStream os;
?
?
?StreamGobbler(InputStream is, String type)
? {
? this(is, type, null);
? }
?
?
?StreamGobbler(InputStream is, String type, OutputStream redirect)
? {
? this.is = is;
? this.type = type;
? this.os = redirect;
? }
?
?
?public void run()
? {
? try
? {
? PrintWriter pw = null;
? if (os != null)
? pw = new PrintWriter(os);
?
?
?InputStreamReader isr = new InputStreamReader(is);
? BufferedReader br = new BufferedReader(isr);
? String line=null;
? while ( (line = br.readLine()) != null)
? {
? if (pw != null)
? pw.println(line);
? System.out.println(type + ">" + line);?
? }
? if (pw != null)
? pw.flush();
? } catch (IOException ioe)
? {
? ioe.printStackTrace();?
? }
? }
? }
?
?
?public class GoodWinRedirect
? {
? public static void main(String args[])
? {
? if (args.length < 1)
? {
? System.out.println("USAGE java GoodWinRedirect ");
? System.exit(1);
? }
?
?
?try
? {?
? FileOutputStream fos = new FileOutputStream(args[0]);
? Runtime rt = Runtime.getRuntime();
? Process proc = rt.exec("java jecho 'Hello World'");
? // any error message?
? StreamGobbler errorGobbler = new?
? StreamGobbler(proc.getErrorStream(), "ERROR");?
?
?
?// any output?
? StreamGobbler outputGobbler = new?
? StreamGobbler(proc.getInputStream(), "OUTPUT", fos);
?
?
?// kick them off
? errorGobbler.start();
? outputGobbler.start();
?
?
?// any error???
? int exitVal = proc.waitFor();
? System.out.println("ExitValue: " + exitVal);
? fos.flush();
? fos.close();?
? } catch (Throwable t)
? {
? t.printStackTrace();
? }
? }
? }
?
?
?Running GoodWinRedirect produces:?
?
?
? E:classescomjavaworldjpitfallsarticle2>java GoodWinRedirect test.txt
? OUTPUT>'Hello World'
? ExitValue: 0
?
?
?這里就不多說了,看看就明白,緊接著作者給出了一個監測命令的小程序
?
?
?import java.util.*;
? import java.io.*;
?
?
?// class StreamGobbler omitted for brevity
?
?
?public class TestExec
? {
? public static void main(String args[])
? {
? if (args.length < 1)
? {
? System.out.println("USAGE: java TestExec "cmd"");
? System.exit(1);
? }
?
?
?try
? {
? String cmd = args[0];
? Runtime rt = Runtime.getRuntime();
? Process proc = rt.exec(cmd);
?
?
?// any error message?
? StreamGobbler errorGobbler = new?
? StreamGobbler(proc.getErrorStream(), "ERR");?
?
?
?// any output?
? StreamGobbler outputGobbler = new?
? StreamGobbler(proc.getInputStream(), "OUT");
?
?
?// kick them off
? errorGobbler.start();
? outputGobbler.start();
?
?
?// any error???
? int exitVal = proc.waitFor();
? System.out.println("ExitValue: " + exitVal);
? } catch (Throwable t)
? {
? t.printStackTrace();
? }
? }
? }
?
?
?對這個程序進行運行:?
? E:classescomjavaworldjpitfallsarticle2>java TestExec "e:javadocsindex.html"
? java.io.IOException: CreateProcess: e:javadocsindex.html error=193
? at java.lang.Win32Process.create(Native Method)
? at java.lang.Win32Process.(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 TestExec.main(TestExec.java:45)
?
?
?193在windows中是說這不是一個win32程序,這說明路徑中找不到這個網頁的關聯程序,下面作者決定用一個絕對路徑來試一下。
?
?
?E:classescomjavaworldjpitfallsarticle2>java TestExec?
? "e:program filesnetscapeprogramnetscape.exe e:javadocsindex.html"
? ExitValue: 0
?
?
? 好用了,這個我也試了一下,用的是IE。
?
?
? 最后,作者總結了幾條規則,防止我們在進行Runtime.exec()調用時出現錯誤。
?
?
??
?
?
??
?
?
?在一個外部進程執行完之前你不能得到他的退出狀態?
?
?
?在你的外部程序開始執行的時候你必須馬上控制輸入、輸出、出錯這些流。?
?
?
?你必須用?
?Runtime.exec()?
?去執行程序?
?
?
?你不能象命令行一樣使用?
?Runtime.exec()?
?。?
?
?
??
?
?
??
?
?
?在nea需要動態來添加到RNC的路由,可以利用Runtime.exec方法來實現
?
?
?具體實現如下:
?
?
?其中的ip參數到時候可以是動態獲取就可以了。
?
?
??
?
?
?String[] cmds = {"cmd.exe","/c","route add 11.11.11.11 mask 255.255.255.255 11.11.11.1 metric 30 > tree.txt"};
?
?
? ? ? ? ?try {?
?
?
? ? ? ? ? ? ?Process ps = Runtime.getRuntime().exec(cmds);?
?
?
? ? ? ? ? ? ?System.out.print(loadStream (ps.getInputStream()));?
?
?
? ? ? ? ? ? ?System.err.print(loadStream (ps.getErrorStream()));?
?
?
? ? ? ? ?} catch(IOException ioe) {?
?
?
? ? ? ? ? ? ?ioe.printStackTrace();?
?
?
? ? ? ? ? }
?
?
??
?
?
? ? ? ? ?// read an input-stream into a String
?
?
? ? ?static String loadStream(InputStream in) throws IOException {?
?
?
? ? ? ? ?int ptr = 0;?
?
?
? ? ? ? ?in = new BufferedInputStream(in);?
?
?
? ? ? ? ?StringBuffer buffer = new StringBuffer();?
?
?
? ? ? ? ?while( (ptr = in.read()) != -1 ) {?
?
?
? ? ? ? ? ? ?buffer.append((char)ptr);?
?
?
? ? ? ? ?}?
?
?
? ? ? ? ?return buffer.toString();?
?
?
? ? ? }
?
?
??
?
?
?其中的 > tree.txt可以把執行這個指令的結果重新定向到一個文件里面,比如執行dir,tree等指令的時候。
?
?
??
?
?
??
?
?
?如果要執行dos以外的指令,需要指定執行工作目錄,
?
?
??
?
?
?比如執行某個exe程序的話,利用了Runtime的
?exec (?
?String [] cmdarray,??
?String [] envp,??
?File? dir)方法來實現。File是這個exe程序的目錄。?
?
?
??
?
?
?String[] cmds = {"cmd.exe","/c","radmin.exe"};
?
?
? ? ? ? ? try {
?
?
? ? ? ? ? ? ?Process ps = Runtime.getRuntime().exec(cmds,null,new File("C://Program Files//Radmin"));?
?
?
? ? ? ? ? ? ?System.out.print(loadStream(ps.getInputStream()));?
?
?
? ? ? ? ? ? ?System.err.print(loadStream(ps.getErrorStream()));?
?
?
? ? ? ? ?} catch(IOException ioe) {?
?
?
? ? ? ? ? ? ?ioe.printStackTrace();?
?
?
? ? ? ? ? }