这篇讲的不错,一起分享!!
或許大部分有寫過Java程式的人都知道java.lang.Runtime這個class有一個method叫做exec(),可以被用來呼叫(調用)外部的程式。然而大部分的人都不知道這個method存在著幾個機車的小陷阱,一個不小心就會發生災難了,待我娓娓道來...
這個method有幾個overloaded的版本如下:
Process |
exec( String[] progArray, String[] envp, File directory)
Executes the specified command and its arguments in a separate native process.
|
Process |
exec( String prog, String[] envp)
Executes the specified program in a separate native process.
|
Process |
exec( String prog)
Executes the specified program in a separate native process.
|
Process |
exec( String prog, String[] envp, File directory)
Executes the specified program in a separate native process.
|
Process |
exec( String[] progArray)
Executes the specified command and its arguments in a separate native process.
|
Process |
exec( String[] progArray, String[] envp)
Executes the specified command and its arguments in a separate native process.
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
import
java.util.*;
import
java.io.*;
public
class
BadExample1 {
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
(Exception e) {
e.printStackTrace ();
}
}
}
|
java BadExample1 java.lang.IllegalThreadStateException: process has not exited at java.lang.Win32Process.exitValue(Native Method) at BadExample1.main(BadExample1.java:13)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
import
java.util.*;
import
java.io.*;
public
class
BadExample2 {
public
static
void
main (String) {
try
{
Runtime rt = Runtime.getRuntime ();
Process proc = rt.exec (
"javac"
);
int
exitVal = proc.waitFor ();
System.out.println (
"Process exitValue: "
+ exitVal);
}
catch
(Exception e) {
e.printStackTrace();
}
}
}
|
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
import
java.util.*;
import
java.io.*;
public
class
OkExample1 {
public
static
void
main (String args[]) {
try
{
Runtime rt = Runtime.getRuntime ();
Process proc = rt.exec (
"javac"
);
String line =
null
;
InputStream stderr = proc.getErrorStream ();
InputStreamReader esr =
new
InputStreamReader (stderr);
BufferedReader ebr =
new
BufferedReader (esr);
System.out.println (
"<error>"
);
while
( (line = ebr.readLine ()) !=
null
)
System.out.println(line);
System.out.println (
"</error>"
);
InputStream stdout = proc.getInputStream ();
InputStreamReader osr =
new
InputStreamReader (stdout);
BufferedReader obr =
new
BufferedReader (osr);
System.out.println (
"<output>"
);
while
( (line = obr.readLine ()) !=
null
)
System.out.println(line);
System.out.println (
"</output>"
);
int
exitVal = proc.waitFor ();
System.out.println (
"Process exitValue: "
+ exitVal);
}
catch
(Exception e) {
e.printStackTrace();
}
}
}
|
java OkExample1 <error> Usage: javac <options> <source files> where <options> 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 <path> Specify where to find user class files -sourcepath <path> Specify where to find input source files -bootclasspath <path> Override location of bootstrap class files -extdirs <dirs> Override location of installed extensions -d <directory> Specify where to place generated class files -encoding <encoding> Specify character encoding used by source files -target <release> Generate class files for specific VM version </error> Process exitValue: 2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
import
java.util.*;
import
java.io.*;
public
class
BadExample3 {
public
static
void
main (String args[]) {
try
{
Runtime rt = Runtime.getRuntime ();
Process proc = rt.exec (
"dir"
);
InputStream stderr = proc.getErrorStream ();
InputStreamReader esr =
new
InputStreamReader (stderr);
BufferedReader ebr =
new
BufferedReader (esr);
System.out.println (
"<error>"
);
while
( (line = ebr.readLine ()) !=
null
)
System.out.println(line);
System.out.println (
"</error>"
);
InputStream stdout = proc.getInputStream ();
InputStreamReader osr =
new
InputStreamReader (stdout);
BufferedReader obr =
new
BufferedReader (osr);
System.out.println (
"<output>"
);
while
( (line = obr.readLine ()) !=
null
)
System.out.println(line);
System.out.println (
"</output>"
);
int
exitVal = proc.waitFor ();
System.out.println (
"Process exitValue: "
+ exitVal);
}
catch
(Exception e) {
e.printStackTrace();
}
}
}
|
java BadExample3 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)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
|
import
java.util.*;
import
java.io.*;
class
StreamConsumer
extends
Thread {
InputStream is;
String type;
StreamConsumer (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
GoodExample1 {
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?
StreamConsumer errorConsumer =
new
StreamConsumer (proc.getErrorStream(),
"error"
);
// any output?
StreamConsumer outputConsumer =
new
StreamConsumer (proc.getInputStream(),
"output"
);
// kick them off
errorConsumer.start ();
outputCosumer.start ();
// any error???
int
exitVal = proc.waitFor ();
System.out.println (
"ExitValue: "
+ exitVal);
}
catch
(Exception e) {
e.printStackTrace ();
}
}
}
|
java GoodExample1 "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:\classes\com\javaworld\jpitfalls\article2 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 ... (省略) 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
import
java.util.*;
import
java.io.*;
public
class
BadExample4 {
public
static
void
main (String args[]) {
try
{
Runtime rt = Runtime.getRuntime ();
Process proc = rt.exec (
"echo 'Hello World' > test.txt"
);
// any error message?
StreamGobbler errorConsumer =
new
StreamConsumer (proc.getErrorStream (),
"error"
);
// any output?
StreamGobbler outputConsumer =
new
StreamConsumer (proc.getInputStream (),
"output"
);
// kick them off
errorConsumer.start();
outputConsumer.start();
// any error???
int
exitVal = proc.waitFor ();
System.out.println (
"ExitValue: "
+ exitVal);
}
catch
(Exception e) {
e.printStackTrace ();
}
}
}
|
java BadExample4 OUTPUT>'Hello World' > test.txt ExitValue: 0