[转载] Java中Runtime的使用
參考鏈接: Java中的JVM的關(guān)閉掛鉤
1? ? ? ? ? ? JDK中Runtime的定義??
?
?
??
?
?
?http://blog.csdn.net/lysnow_oss/archive/2007/05/12/1606349.aspx
??
?
?
?<轉(zhuǎn)載>
?
?
?那就首先說(shuō)點(diǎn)Runtime類吧,他是一個(gè)與JVM運(yùn)行時(shí)環(huán)境有關(guān)的類,這個(gè)類是Singleton的。我說(shuō)幾個(gè)自己覺得重要的地方。
?
?
?1、Runtime.getRuntime()可以取得當(dāng)前JVM的運(yùn)行時(shí)環(huán)境,這也是在Java中唯一一個(gè)得到運(yùn)行時(shí)環(huán)境的方法。
?
?
?2、Runtime上其他大部分的方法都是實(shí)例方法,也就是說(shuō)每次進(jìn)行運(yùn)行時(shí)調(diào)用時(shí)都要用到getRuntime方法。
?
?
?3、Runtime中的exit方法是退出當(dāng)前JVM的方法,估計(jì)也是唯一的一個(gè)吧,因?yàn)槲铱吹絊ystem類中的exit實(shí)際上也是通過(guò)調(diào)用 Runtime.exit()來(lái)退出JVM的,這里說(shuō)明一下Java對(duì)Runtime返回值的一般規(guī)則(后邊也提到了),0代表正常退出,非0代表異常中 止,這只是Java的規(guī)則,在各個(gè)操作系統(tǒng)中總會(huì)發(fā)生一些小的混淆。
?
?
??
?
?
?4、Runtime.addShutdownHook()方法可以注冊(cè)一個(gè)hook在JVM執(zhí)行shutdown的過(guò)程中,方法的參數(shù)只要是一個(gè)初始化過(guò)但是沒有執(zhí)行的Thread實(shí)例就可以。(注意,Java中的Thread都是執(zhí)行過(guò)了就不值錢的哦)
?
?
?5、說(shuō)到addShutdownHook這個(gè)方法就要說(shuō)一下JVM運(yùn)行環(huán)境是在什么情況下shutdown或者abort的。文檔上是這樣寫 的,當(dāng)最后一個(gè)非精靈進(jìn)程退出或者收到了一個(gè)用戶中斷信號(hào)、用戶登出、系統(tǒng)shutdown、Runtime的exit方法被調(diào)用時(shí)JVM會(huì)啟動(dòng) shutdown的過(guò)程,在這個(gè)過(guò)程開始后,他會(huì)并行啟動(dòng)所有登記的shutdown hook(注意是并行啟動(dòng),這就需要線程安全和防止死鎖)。當(dāng)shutdown過(guò)程啟動(dòng)后,只有通過(guò)調(diào)用halt方法才能中止shutdown的過(guò)程并退 出JVM。
?
?
?那什么時(shí)候JVM會(huì)abort退出那?首先說(shuō)明一下,abort退出時(shí)JVM就是停止運(yùn)行但并不一定進(jìn)行shutdown。這只有JVM在遇到 SIGKILL信號(hào)或者windows中止進(jìn)程的信號(hào)、本地方法發(fā)生類似于訪問(wèn)非法地址一類的內(nèi)部錯(cuò)誤時(shí)會(huì)出現(xiàn)。這種情況下并不能保證shutdown hook是否被執(zhí)行。
?
?
??
?
?
?首先講的是?
?Runtime.exec()?
?方法的所有重載。這里要注意的有一點(diǎn),就是?
?public Process exec(String [] cmdArray, String [] envp);?
?這個(gè)方法中?
?cmdArray?
?是一個(gè)執(zhí)行的命令和參數(shù)的字符串?dāng)?shù)組,數(shù)組的第一個(gè)元素是要執(zhí)行的命令往后依次都是命令的參數(shù),?
?envp?
?我個(gè)人感覺應(yīng)該和?
?C?
?中的?
?execve?
?中的環(huán)境變量是一樣的,?
?envp?
?中使用的是?
?name=value?
?的方式。?
?
?
??
?
?
?2? ? ? ? ? ? Runtime的構(gòu)造函數(shù)和方法??
?
?
??
?
?
?Runtime是個(gè)單例類
?
?
??
?
?
? ??
? ? ?方法摘要
? ? ??
? ??
? ? ? void
? ? ??
? ??
? ? ?addShutdownHook 注冊(cè)新的虛擬機(jī)來(lái)關(guān)閉掛鉤。 (
? ? ?Thread? ?hook)?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ? int
? ? ??
? ??
? ? ?availableProcessors 向 Java 虛擬機(jī)返回可用處理器的數(shù)目。 ()?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ??
? ? ?Process??
? ? ??
? ??
? ? ?exec 在單獨(dú)的進(jìn)程中執(zhí)行指定的字符串命令。 (
? ? ?String? ?command)?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ??
? ? ?Process??
? ? ??
? ??
? ? ?exec 在單獨(dú)的進(jìn)程中執(zhí)行指定命令和變量。 (
? ? ?String? [] cmdarray)?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ??
? ? ?Process??
? ? ??
? ??
? ? ?exec 在指定環(huán)境的獨(dú)立進(jìn)程中執(zhí)行指定命令和變量。 (
? ? ?String? [] cmdarray,?
? ? ?String? [] envp)?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ??
? ? ?Process??
? ? ??
? ??
? ? ?exec 在指定環(huán)境和工作目錄的獨(dú)立進(jìn)程中執(zhí)行指定的命令和變量。 (
? ? ?String? [] cmdarray,?
? ? ?String? [] envp,?
? ? ?File? ?dir)?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ??
? ? ?Process??
? ? ??
? ??
? ? ?exec 在指定環(huán)境的單獨(dú)進(jìn)程中執(zhí)行指定的字符串命令。 (
? ? ?String? ?command,?
? ? ?String? [] envp)?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ??
? ? ?Process??
? ? ??
? ??
? ? ?exec 在有指定環(huán)境和工作目錄的獨(dú)立進(jìn)程中執(zhí)行指定的字符串命令。 (
? ? ?String? ?command,?
? ? ?String? [] envp,?
? ? ?File? ?dir)?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ? void
? ? ??
? ??
? ? ?exit 通過(guò)啟動(dòng)虛擬機(jī)的關(guān)閉序列,終止當(dāng)前正在運(yùn)行的 Java 虛擬機(jī)。 (int status)?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ? long
? ? ??
? ??
? ? ?freeMemory 返回 Java 虛擬機(jī)中的空閑內(nèi)存量。 ()?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ? void
? ? ??
? ??
? ? ?gc 運(yùn)行垃圾回收器。 ()?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ??
? ? ?InputStream??
? ? ??
? ??
? ? ?getLocalizedInputStream 已過(guò)時(shí)。 從 JDK 1.1 開始,將本地編碼字節(jié)流轉(zhuǎn)換為 Unicode 字符流的首選方法是使用 InputStreamReader 和 BufferedReader 類。 (
? ? ?InputStream? ?in)?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ??
? ? ?OutputStream??
? ? ??
? ??
? ? ?getLocalizedOutputStream 已過(guò)時(shí)。 從 JDK 1.1 開始,將 Unicode 字符流轉(zhuǎn)換為本地編碼字節(jié)流的首選方法是使用 OutputStreamWriter、BufferedWriter 和 PrintWriter 類。 (
? ? ?OutputStream? ?out)?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ?static?
? ? ?Runtime??
? ? ??
? ??
? ? ?getRuntime 返回與當(dāng)前 Java 應(yīng)用程序相關(guān)的運(yùn)行時(shí)對(duì)象。 ()?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ? void
? ? ??
? ??
? ? ?halt 強(qiáng)行終止目前正在運(yùn)行的 Java 虛擬機(jī)。 (int status)?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ? void
? ? ??
? ??
? ? ?load 加載作為動(dòng)態(tài)庫(kù)的指定文件名。 (
? ? ?String? ?filename)?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ? void
? ? ??
? ??
? ? ?loadLibrary 加載具有指定庫(kù)名的動(dòng)態(tài)庫(kù)。 (
? ? ?String? ?libname)?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ? long
? ? ??
? ??
? ? ?maxMemory 返回 Java 虛擬機(jī)試圖使用的最大內(nèi)存量。 ()?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ? boolean
? ? ??
? ??
? ? ?removeShutdownHook 取消注冊(cè)某個(gè)先前已注冊(cè)的虛擬機(jī)關(guān)閉掛鉤。 (
? ? ?Thread? ?hook)?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ? void
? ? ??
? ??
? ? ?runFinalization 運(yùn)行掛起 finalization 的所有對(duì)象的終止方法。 ()?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ?static void
? ? ??
? ??
? ? ?runFinalizersOnExit 已過(guò)時(shí)。 此方法本身具有不安全性。它可能對(duì)正在使用的對(duì)象調(diào)用終結(jié)方法,而其他線程正在操作這些對(duì)象,從而導(dǎo)致不正確的行為或死鎖。 (boolean value)?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ? long
? ? ??
? ??
? ? ?totalMemory 返回 Java 虛擬機(jī)中的內(nèi)存總量。 ()?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ? void
? ? ??
? ??
? ? ?traceInstructions 啟用/禁用指令跟蹤。 (boolean on)?
? ? ? ? ? ? ? ??
? ? ??
? ??
? ? ? void
? ? ??
? ??
? ? ?traceMethodCalls 啟用/禁用方法調(diào)用跟蹤。 (boolean on)?
? ? ? ? ? ? ? ??
? ? ??
?
??
?
?
?3? ? ? ? ? ? Runtime的使用??
?
?
?這個(gè)程序用exec調(diào)用了一個(gè)外部命令之后馬上使用exitValue就對(duì)其返回值進(jìn)行檢查,讓我們看看會(huì)出現(xiàn)什么問(wèn)題。
?
?
??
?
?
?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)
?
?
??
?
?
?這里看原文就可以了解,這里主要的問(wèn)題就是錯(cuò)誤的調(diào)用了exitValue來(lái)取得外部命令的返回值(呵呵,這個(gè)錯(cuò)誤我也曾經(jīng)犯過(guò)),因?yàn)?exitValue這個(gè)方法是不阻塞的,程序在調(diào)用這個(gè)方法時(shí)外部命令并沒有返回所以造成了異常的出現(xiàn),這里是由另外的方法來(lái)等待外部命令執(zhí)行完畢的,就 是waitFor方法,這個(gè)方法會(huì)一直阻塞直到外部命令執(zhí)行結(jié)束,然后返回外部命令執(zhí)行的結(jié)果,作者在這里一頓批評(píng)設(shè)計(jì)者的思路有問(wèn)題,呵呵,反正我是無(wú) 所謂阿,能用就可以拉。但是作者在這里有一個(gè)說(shuō)明,就是exitValue也是有好多用途的。因?yàn)楫?dāng)你在一個(gè)Process上調(diào)用waitFor方法時(shí), 當(dāng)前線程是阻塞的,如果外部命令無(wú)法執(zhí)行結(jié)束,那么你的線程就會(huì)一直阻塞下去,這種意外會(huì)影響我們程序的執(zhí)行。所以在我們不能判斷外部命令什么時(shí)候執(zhí)行完 畢而我們的程序還需要繼續(xù)執(zhí)行的情況下,我們就應(yīng)該循環(huán)的使用exitValue來(lái)取得外部命令的返回狀態(tài),并在外部命令返回時(shí)作出相應(yīng)的處理。
?
?
??
?
?
?2、對(duì)exitValue處改進(jìn)了的程序
?
?
?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();
? }
? }
? }
?
?
?不幸的是,這個(gè)程序也無(wú)法執(zhí)行完成,它沒有輸出但卻一直懸在那里,這是為什么那?
?
?
? JDK文檔中對(duì)此有如此的解釋:因?yàn)楸镜氐南到y(tǒng)對(duì)標(biāo)準(zhǔn)輸入和輸出所提供的緩沖池有效,所以錯(cuò)誤的對(duì)標(biāo)準(zhǔn)輸出快速的寫入和從標(biāo)準(zhǔn)輸入快速的讀入都有可能造成子進(jìn)程的鎖,甚至死鎖。
?
?
? 文檔引述完了,作者又開始批評(píng)了,他說(shuō)JDK僅僅說(shuō)明為什么問(wèn)題會(huì)發(fā)生,卻并沒有說(shuō)明這個(gè)問(wèn)題怎么解決,這的確是個(gè)問(wèn)題哈。緊接著作者 說(shuō)出自己的做法,就是在執(zhí)行完外部命令后我們要控制好Process的所有輸入和輸出(視情況而定),在這個(gè)例子里邊因?yàn)檎{(diào)用的是Javac,而他在沒有 參數(shù)的情況下會(huì)將提示信息輸出到標(biāo)準(zhǔn)出錯(cuò),所以在下面的程序中我們要對(duì)此進(jìn)行處理。
?
?
? 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();
? }
? }
? }
?
?
? 程序的運(yùn)行結(jié)果為
?
?
?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
?
?
? 哎,不管怎么說(shuō)還是出來(lái)了結(jié)果,作者作了一下總結(jié),就是說(shuō),為了處理好外部命令大量輸出的情況,你要確保你的程序處理好外部命令所需要的輸入或者輸出。
?
?
? 下一個(gè)題目,當(dāng)我們調(diào)用一個(gè)我們認(rèn)為是可執(zhí)行程序的時(shí)候容易發(fā)生的錯(cuò)誤(今天晚上我剛剛犯這個(gè)錯(cuò)誤,沒事做這個(gè)練習(xí)時(shí)候發(fā)生的)
?
?
?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)
?
?
? 說(shuō)實(shí)在的,這個(gè)錯(cuò)誤還真是讓我摸不著頭腦,我覺得在windows中返回2應(yīng)該是沒有找到這個(gè)文件的緣故,可能windows 2000中只有cmd命令,dir命令不是當(dāng)前環(huán)境變量能夠解釋的吧。我也不知道了,慢慢往下看吧。
?
?
?嘿,果然和作者想的一樣,就是因?yàn)閐ir命令是由windows中的解釋器解釋的,直接執(zhí)行dir時(shí)無(wú)法找到dir.exe這個(gè)命令,所以會(huì)出 現(xiàn)文件未找到這個(gè)2的錯(cuò)誤。如果我們要執(zhí)行這樣的命令,就要先根據(jù)操作系統(tǒng)的不同執(zhí)行不同的解釋程序command.com 或者cmd.exe。
?
?
?作者對(duì)上邊的程序進(jìn)行了修改
?
?
?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
?
?
?這里作者教了一個(gè)windows中很有用的方法,呵呵,至少我是不知道的,就是cmd.exe /C +一個(gè)windows中注冊(cè)了后綴的文檔名,windows會(huì)自動(dòng)地調(diào)用相關(guān)的程序來(lái)打開這個(gè)文檔,我試了一下,的確很好用,但是好像文件路徑中有空格的 話就有點(diǎn)問(wèn)題,我加上引號(hào)也無(wú)法解決。
?
?
?這里作者強(qiáng)調(diào)了一下,不要假設(shè)你執(zhí)行的程序是可執(zhí)行的程序,要清楚自己的程序是單獨(dú)可執(zhí)行的還是被解釋的,本章的結(jié)束作者會(huì)介紹一個(gè)命令行工具來(lái)幫助我們分析。
?
?
?這里還有一點(diǎn),就是得到process的輸出的方式是getInputStream,這是因?yàn)槲覀円獜腏ava 程序的角度來(lái)看,外部程序的輸出對(duì)于Java來(lái)說(shuō)就是輸入,反之亦然。
?
?
? 最后的一個(gè)漏洞的地方就是錯(cuò)誤的認(rèn)為exec方法會(huì)接受所有你在命令行或者Shell中輸入并接受的字符串。這些錯(cuò)誤主要出現(xiàn)在命令作 為參數(shù)的情況下,程序員錯(cuò)誤的將所有命令行中可以輸入的參數(shù)命令加入到exec中(這段翻譯的不好,湊合看吧)。下面的例子中就是一個(gè)程序員想重定向一個(gè) 命令的輸出。
?
?
? 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這個(gè)輸入重訂向到一個(gè)文本文件中,但是這個(gè)文件并沒有生成,jecho僅僅是將命令行中的參數(shù)輸出到標(biāo)準(zhǔn)輸出中,用戶覺得可以像dos中重定向 一樣將輸出重定向到一個(gè)文件中,但這并不能實(shí)現(xiàn),用戶錯(cuò)誤的將exec認(rèn)為是一個(gè)shell解釋器,但它并不是,如果你想將一個(gè)程序的輸出重定向到其他的 程序中,你必須用程序來(lái)實(shí)現(xiàn)他。可用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
?
?
?這里就不多說(shuō)了,看看就明白,緊接著作者給出了一個(gè)監(jiān)測(cè)命令的小程序
?
?
?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();
? }
? }
? }
?
?
?對(duì)這個(gè)程序進(jìn)行運(yùn)行:?
? 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中是說(shuō)這不是一個(gè)win32程序,這說(shuō)明路徑中找不到這個(gè)網(wǎng)頁(yè)的關(guān)聯(lián)程序,下面作者決定用一個(gè)絕對(duì)路徑來(lái)試一下。
?
?
?E:classescomjavaworldjpitfallsarticle2>java TestExec?
? "e:program filesnetscapeprogramnetscape.exe e:javadocsindex.html"
? ExitValue: 0
?
?
? 好用了,這個(gè)我也試了一下,用的是IE。
?
?
? 最后,作者總結(jié)了幾條規(guī)則,防止我們?cè)谶M(jìn)行Runtime.exec()調(diào)用時(shí)出現(xiàn)錯(cuò)誤。
?
?
??
?
?
??
?
?
?在一個(gè)外部進(jìn)程執(zhí)行完之前你不能得到他的退出狀態(tài)?
?
?
?在你的外部程序開始執(zhí)行的時(shí)候你必須馬上控制輸入、輸出、出錯(cuò)這些流。?
?
?
?你必須用?
?Runtime.exec()?
?去執(zhí)行程序?
?
?
?你不能象命令行一樣使用?
?Runtime.exec()?
?。?
?
?
??
?
?
??
?
?
?在nea需要?jiǎng)討B(tài)來(lái)添加到RNC的路由,可以利用Runtime.exec方法來(lái)實(shí)現(xiàn)
?
?
?具體實(shí)現(xiàn)如下:
?
?
?其中的ip參數(shù)到時(shí)候可以是動(dòng)態(tài)獲取就可以了。
?
?
??
?
?
?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可以把執(zhí)行這個(gè)指令的結(jié)果重新定向到一個(gè)文件里面,比如執(zhí)行dir,tree等指令的時(shí)候。
?
?
??
?
?
??
?
?
?如果要執(zhí)行dos以外的指令,需要指定執(zhí)行工作目錄,
?
?
??
?
?
?比如執(zhí)行某個(gè)exe程序的話,利用了Runtime的
?exec (?
?String [] cmdarray,??
?String [] envp,??
?File? dir)方法來(lái)實(shí)現(xiàn)。File是這個(gè)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();?
?
?
? ? ? ? ? }
總結(jié)
以上是生活随笔為你收集整理的[转载] Java中Runtime的使用的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: linux磁盘fio压力测试,fio进行
- 下一篇: java和cnc_Java程序员的目标,