使用Runtime.getRuntime().exec()方法的幾個陷阱


Process 子類的一個實例,該實例可用來控制進程並獲得相關信息。Process 類提供了執行從進程輸入、執行輸出到進程、等待進程完成、檢查進程的退出狀態以及銷毀(殺掉)進程的方法。 創建進程的方法可能無法針對某些本機平台上的特定進程很好地工作,比如,本機窗口進程,守護進程,Microsoft Windows 上的 Win16/DOS 進程,或者 shell 腳本。
創建的子進程沒有自己的終端或控制台

它的所有標准 io(即 stdin、stdout 和 stderr)操作都將通過三個流 (getOutputStream()、getInputStream() 和 getErrorStream()) 重定向到父進程。

子線程的輸入是主線程提供的,這個數據對主線程來說就是輸出,即jvm線程的OutputStream數據是子線程的stdin;主線程的InputStream是子線程的stdout

 

父進程使用這些流來提供到子進程的輸入和獲得從子進程的輸出。因為有些本機平台僅針對標准輸入和輸出流提供有限的緩沖區大小,如果讀寫子進程的輸出流或輸入流迅速出現失敗,則可能導致子進程阻塞,甚至產生死鎖。 當沒有 Process 對象的更多引用時,不是刪掉子進程,而是繼續異步執行子進程。 對於帶有 Process 對象的 Java 進程,沒有必要異步或並發執行由 Process 對象表示的進程。

The class java.lang.Runtime features a static method called getRuntime(), which retrieves the current Java Runtime Environment.
That is the only way to obtain a reference to the Runtime object. With that 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 versions 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); 

一個能用的demo:
原則:就是讓標准輸出和錯誤輸出都使用專門的線程處理,這樣可以避免子線程阻塞而導致的錯誤。建議使用proc.waitFor()

調用的地方:

 1 public boolean execCommand(String commnad) {
 2         try {
 3             Runtime rt = Runtime.getRuntime();
 4             Process proc = rt.exec(cmd);
 5             OutputProcessor error = new OutputProcessor(proc.getErrorStream());
 6             OutputProcessor input = new OutputProcessor(proc.getInputStream());
 7             error.start();
 8             input.start();
 9             int exitCode = proc.waitFor();
10             if (exitCode == 0) {
11                 return true;
12             }
13             return false;
14         } catch (Exception e) {
15             LOGGER.info("{}", e.getMessage(), e);
16             return false;
17         }
18     }

處理標准輸出和錯誤輸出的線程,因為就是防止子線程阻塞,沒簡單的輸出沒有特殊處理:

 1 class OutputProcessor extends Thread {
 2     private static final Logger LOGGER = LoggerFactory.getLogger(OutputProcessor.class);
 3     private InputStream inputStream;
 4 
 5     public OutputProcessor(InputStream inputStream) {
 6         this.inputStream = inputStream;
 7     }
 8 
 9     @Override
10     public void run() {
11         try {
12             InputStreamReader isr = new InputStreamReader(inputStream);
13             BufferedReader br = new BufferedReader(isr);
14             String line;
15             while ((line = br.readLine()) != null) {
16                 LOGGER.info("{}", line);
17             }
18         } catch (Exception e) {
19             LOGGER.error("", e.getMessage(), e);
20         }
21     }
22 }

1.Stumbling into an IllegalThreadStateException 
The first pitfall relating to Runtime.exec() is the IllegalThreadStateException. 

 1 import java.util.*;
 2 import java.io.*;
 3 public class BadExecJavac
 4 {
 5     public static void main(String args[])
 6     {
 7         try
 8         {            
 9             Runtime rt = Runtime.getRuntime();
10             Process proc = rt.exec("javac");
11             int exitVal = proc.exitValue();
12             System.out.println("Process exitValue: " + exitVal);
13         } catch (Throwable t){t.printStackTrace();}
14     }
15 }

If an external process has not yet completed, the exitValue() method will throw an IllegalThreadStateException; that's why this program failed. While the documentation states this fact, why can't this method wait until it can give a valid answer? 
 
A more thorough look at the methods available in the Process class reveals a waitFor() method that does precisely that. In fact, waitFor() also returns the exit value, which means that you would not use exitValue() and waitFor() in conjunction with each other, but rather would choose one or the other. 
The only possible time you would use exitValue() instead of waitFor() would be 
when you don't want your program to block waiting on an external process that may never complete.

 1 import java.util.*;
 2 import java.io.*;
 3 
 4 public class BadExecJavac2
 5 {
 6     public static void main(String args[])
 7     {
 8         try
 9         {            
10             Runtime rt = Runtime.getRuntime();
11             Process proc = rt.exec("javac");
12             int exitVal = proc.waitFor();
13             System.out.println("Process exitValue: " + exitVal);
14         } catch (Throwable t){t.printStackTrace();}
15     }
16 }

Unfortunately, a run of BadExecJavac2 produces no output. The program hangs and never completes. 
Why does the javac process never complete? 
Why Runtime.exec() hangs 
The JDK's Javadoc documentation provides the answer to this question: 
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
本地平台為標准的輸入輸出流只能提供有限的buffer,因此就不能夠立即寫子進程的輸入流或者是讀取子進程的輸出流,這就會導致子進程的阻塞甚至死鎖

 1 import java.util.*;
 2 import java.io.*;
 3 public class MediocreExecJavac
 4 {
 5     public static void main(String args[])
 6     {
 7         try
 8         {            
 9             Runtime rt = Runtime.getRuntime();
10             Process proc = rt.exec("javac");
11             InputStream stderr = proc.getErrorStream();
12             InputStreamReader isr = new InputStreamReader(stderr);
13             BufferedReader br = new BufferedReader(isr);
14             String line = null;
15             System.out.println("<ERROR>");
16             while ( (line = br.readLine()) != null)
17                 System.out.println(line);
18             System.out.println("</ERROR>");
19             int exitVal = proc.waitFor();
20             System.out.println("Process exitValue: " + exitVal);
21         } catch (Throwable t){t.printStackTrace();}
22     }
23 }

So, MediocreExecJavac works and produces an exit value of 2. Normally, an exit value of indicates success; any nonzero value indicates an error. The meaning of these exit values depends on the particular operating system.
Thus, to circumvent the second pitfall 
                                                  -- hanging forever in Runtime.exec() --
 if the program you launch produces output or expects input, ensure that you process the input and output streams. 

3.Assuming a command is an executable program

 1 import java.util.*;
 2 import java.io.*;
 3 
 4 public class BadExecWinDir
 5 {
 6     public static void main(String args[])
 7     {
 8         try
 9         {            
10             Runtime rt = Runtime.getRuntime();
11             Process proc = rt.exec("dir");//must run as rt.exec("cmd /C dir");
12             InputStream stdin = proc.getInputStream();//輸入或輸出是以jvm為參照物的,命令執行結果會輸出到Jvm,對jvm來說命令的輸出就是jvm的輸入
13             InputStreamReader isr = new InputStreamReader(stdin);
14             BufferedReader br = new BufferedReader(isr);
15             String line;
16             System.out.println("<OUTPUT>");
17             while ( (line = br.readLine()) != null)
18                 System.out.println(line);
19             System.out.println("</OUTPUT>");
20             int exitVal = proc.waitFor();            
21             System.out.println("Process exitValue: " + exitVal);
22         } catch (Throwable t)
23           {
24             t.printStackTrace();
25           }
26     }
27 }

java BadExecWinDir
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)
That's because the directory command is part of the Windows command interpreter and not a separate executable
To run the Windows command interpreter, execute either command.com or cmd.exe, depending on the Windows operating system you use.

 1 import java.util.*;
 2 import java.io.*;
 3 
 4 class StreamGobbler extends Thread
 5 {
 6     InputStream is;
 7     String type;
 8     
 9     StreamGobbler(InputStream is, String type)
10     {
11         this.is = is;
12         this.type = type;
13     }
14     
15     public void run()
16     {
17         try
18         {
19             InputStreamReader isr = new InputStreamReader(is);
20             BufferedReader br = new BufferedReader(isr);
21             String line=null;
22             while ( (line = br.readLine()) != null)
23                 System.out.println(type + ">" + line);    
24             } catch (IOException ioe)
25               {
26                 ioe.printStackTrace();  
27               }
28     }
29 }
30 
31 public class GoodWindowsExec
32 {
33     public static void main(String args[])
34     {
35         if (args.length < 1)
36         {
37             System.out.println("USAGE: java GoodWindowsExec <cmd>");
38             System.exit(1);
39         }
40         
41         try
42         {            
43             String osName = System.getProperty("os.name" );
44             String[] cmd = new String[3];
45 
46             if( osName.equals( "Windows NT" ) )
47             {
48                 cmd[0] = "cmd.exe" ;
49                 cmd[1] = "/C" ;
50                 cmd[2] = args[0];
51             }
52             else if( osName.equals( "Windows 95" ) )
53             {
54                 cmd[0] = "command.com" ;
55                 cmd[1] = "/C" ;
56                 cmd[2] = args[0];
57             }
58             
59             Runtime rt = Runtime.getRuntime();
60             System.out.println("Execing " + cmd[0] + " " + cmd[1] 
61                                + " " + cmd[2]);
62             Process proc = rt.exec(cmd);
63             // any error message?
64             StreamGobbler errorGobbler = new 
65                 StreamGobbler(proc.getErrorStream(), "ERROR");            
66             
67             // any output?
68             StreamGobbler outputGobbler = new 
69                 StreamGobbler(proc.getInputStream(), "OUTPUT");
70                 
71             // kick them off
72             errorGobbler.start();
73             outputGobbler.start();
74                                     
75             // any error???
76             int exitVal = proc.waitFor();
77             System.out.println("ExitValue: " + exitVal);        
78         } catch (Throwable t)
79           {
80             t.printStackTrace();
81           }
82     }
83 }

java GoodWindowsExec "dir *.java"
Running GoodWindowsExec with any associated document type will launch the application associated with that document type.
 For example, to launch Microsoft Word to display a Word document (i.e., one with a .doc extension), type: 
>java GoodWindowsExec "yourdoc.doc"
Thus, to avoid the third pitfall related to Runtime.exec(), do not assume that a command is an executable program; know whether you are executing a standalone executable or an interpreted command
It is important to note that the method used to obtain a process's output stream is called getInputStream(). The thing to remember is that the API sees things from the perspective of the Java program and not the external process. Therefore, the external program's output is the Java program's input. And that logic carries over to the external program's input stream, which is an output stream to the Java program. 

4.Runtime.exec() is not a command line One final pitfall to cover with Runtime.exec() is mistakenly assuming that exec() accepts any String that your command line (or shell) accepts. Runtime.exec() is much more limited and not cross-platform

 1 import java.util.*;
 2 import java.io.*;
 3 
 4 // StreamGobbler omitted for brevity
 5 
 6 public class BadWinRedirect
 7 {
 8     public static void main(String args[])
 9     {
10         try
11         {            
12             Runtime rt = Runtime.getRuntime();
13             Process proc = rt.exec("java jecho 'Hello World' > test.txt");
14             // any error message?
15             StreamGobbler errorGobbler = new 
16                 StreamGobbler(proc.getErrorStream(), "ERROR");            
17             
18             // any output?
19             StreamGobbler outputGobbler = new 
20                 StreamGobbler(proc.getInputStream(), "OUTPUT");
21                 
22             // kick them off
23             errorGobbler.start();
24             outputGobbler.start();
25                                     
26             // any error???
27             int exitVal = proc.waitFor();
28             System.out.println("ExitValue: " + exitVal);        
29         } catch (Throwable t)
30           {
31             t.printStackTrace();
32           }
33     }
34 }
1 java BadWinRedirect
2 OUTPUT>'Hello World' > test.txt
3 ExitValue: 0
4 The program BadWinRedirect attempted to redirect the output of an echo program's simple Java version into the file test.txt. However, we find that the file test.txt does not exist. The jecho program simply takes its command-line arguments and writes them to the standard output stream. 
5 Instead, exec() executes a single executable (a program or script). If you want to process the stream to either redirect it or pipe it into another program, you must do so programmatically, using the java.io package.
 1 import java.util.*;
 2 import java.io.*;
 3 
 4 class StreamGobbler extends Thread
 5 {
 6     InputStream is;
 7     String type;
 8     OutputStream os;
 9     
10     StreamGobbler(InputStream is, String type)
11     {
12         this(is, type, null);
13     }
14 
15     StreamGobbler(InputStream is, String type, OutputStream redirect)
16     {
17         this.is = is;
18         this.type = type;
19         this.os = redirect;
20     }
21     
22     public void run()
23     {
24         try
25         {
26             PrintWriter pw = null;
27             if (os != null)
28                 pw = new PrintWriter(os);
29                 
30             InputStreamReader isr = new InputStreamReader(is);
31             BufferedReader br = new BufferedReader(isr);
32             String line=null;
33             while ( (line = br.readLine()) != null)
34             {
35                 if (pw != null)
36                     pw.println(line);
37                 System.out.println(type + ">" + line);    
38             }
39             if (pw != null)
40                 pw.flush();
41         } catch (IOException ioe)
42             {
43             ioe.printStackTrace();  
44             }
45     }
46 }
47 
48 public class GoodWinRedirect
49 {
50     public static void main(String args[])
51     {
52         if (args.length < 1)
53         {
54             System.out.println("USAGE java GoodWinRedirect <outputfile>");
55             System.exit(1);
56         }
57         
58         try
59         {            
60             FileOutputStream fos = new FileOutputStream(args[0]);
61             Runtime rt = Runtime.getRuntime();
62             Process proc = rt.exec("java jecho 'Hello World'");
63             // any error message?
64             StreamGobbler errorGobbler = new 
65                 StreamGobbler(proc.getErrorStream(), "ERROR");            
66             
67             // any output?
68             StreamGobbler outputGobbler = new 
69                 StreamGobbler(proc.getInputStream(), "OUTPUT", fos);
70                 
71             // kick them off
72             errorGobbler.start();
73             outputGobbler.start();
74                                     
75             // any error???
76             int exitVal = proc.waitFor();
77             System.out.println("ExitValue: " + exitVal);
78             fos.flush();
79             fos.close();        
80         } catch (Throwable t)
81           {
82             t.printStackTrace();
83           }
84     }
85 }

java GoodWinRedirect test.txt
The solution to the pitfall was to simply control the redirection by handling the external process's standard output stream separately from the Runtime.exec() method. 
before finalizing arguments to Runtime.exec() and writing the code, quickly test the arguments. Listing 4.8 is a simple command-line utility that allows you to do just that. 

 

 1 import java.util.*;
 2 import java.io.*;
 3 
 4 // class StreamGobbler omitted for brevity
 5 
 6 public class TestExec
 7 {
 8     public static void main(String args[])
 9     {
10         if (args.length < 1)
11         {
12             System.out.println("USAGE: java TestExec \"cmd\"");
13             System.exit(1);
14         }
15         
16         try
17         {
18             String cmd = args[0];
19             Runtime rt = Runtime.getRuntime();
20             Process proc = rt.exec(cmd);
21             
22             // any error message?
23             StreamGobbler errorGobbler = new 
24                 StreamGobbler(proc.getErrorStream(), "ERR");            
25             
26             // any output?
27             StreamGobbler outputGobbler = new 
28                 StreamGobbler(proc.getInputStream(), "OUT");
29                 
30             // kick them off
31             errorGobbler.start();
32             outputGobbler.start();
33                                     
34             // any error???
35             int exitVal = proc.waitFor();
36             System.out.println("ExitValue: " + exitVal);
37         } catch (Throwable t)
38           {
39             t.printStackTrace();
40           }
41     }
42 }

java TestExec "explorer.exe aa.html"
To sum up, follow these rules of thumb to avoid the pitfalls in Runtime.exec(): 
1.      You cannot obtain an exit status from an external process until it has exited 
2.      You must immediately handle the input, output, and error streams from your spawned external process 
3.      You must use Runtime.exec() to execute programs 
4.      You cannot use Runtime.exec() like a command line 

 

http://web4.blog.163.com/blog/static/1896941312009124102715446/

http://tech.it168.com/j/2006-04-29/200604291539038.shtml

 

Runtime.exec() 不等同於直接執行command line命令!

Runtime.exec()很有局限性,對有些命令不能直接把command line里的內容當作String參數傳給exec().

比如重定向等命令。舉個例子:

javap -l xxx > output.txt

這時要用到exec的第二種重載,即input 參數為String[]:

Process p = Runtime.getRuntime().exec(new String[]{"/bin/sh","-c","javap -l xxx > output.txt"});

rm -rf name*

Process p = Runtime.getRuntime().exec(new String[]{"/bin/sh","-c","rm -rf name*"});

 

http://www.cnblogs.com/rspb/p/4648917.html

 

Runtime 封裝着java程序的運行時環境。通過Runtime實例,java應用能夠與其運行的環境連接。Runtime在jvm中保持一個單例,所以不能通過Runtime類的構造函數。只能通過Runtime.getRuntime()來獲的當前Runtime的一個實例。獲得Runtime實例后,就可以通過Runtime的exec()方法在當前jvm進程外啟動其他進程了。很常見的一個應用就是,啟動瀏覽器進程來顯示一個程序的幫助頁面。 

在Runtime類中存在四個exec()重載方法.

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編譯器進程。

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標志,來確定使用哪個。運行下面的代碼:

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. 
翻譯: 
一些平台只為標准輸入輸出提供有限的緩存。錯誤的寫子進程的輸入流或者錯誤的都子進程的輸出流都有可能造成子進程的阻塞,甚至是死鎖。 

解決上面問題的辦法就是程序中將子進程的輸出流和錯誤流都輸出到標准輸出中。

 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;

 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的系統的版本。

 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()並不是命令解析器,這是啟動某個進程。並不能執行一些命令行的命令。下面是一個常見的錯誤:

 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()並不是命令行解析器。要想重定向輸出流,必須在程序中編碼實現。

 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 }  

 

http://www.cnblogs.com/nkxyf/archive/2012/12/13/2815978.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM