Java调用系统命令学习(3)

学习了两篇的Runtime类,现在对它有了更深一层的了解,那么我们来看看下面的代码:
Java代码   收藏代码
  1. import java.io.IOException;  
  2. import java.io.InputStream;  
  3. import java.io.InputStreamReader ;  
  4. import java.io.BufferedReader;  
  5. public class Exec_Output{  
  6.         public static void main(String []args)throws IOException,InterruptedException{  
  7.                 Runtime rt = Runtime.getRuntime();  
  8.                 Process p = rt.exec("dir");  
  9.                 //int exitValue = p.exitValue();  
  10.                 //int exitValue = p.waitFor();  
  11.                 InputStream is = p.getInputStream();  
  12.                 InputStreamReader isr = new InputStreamReader(is);  
  13.                 BufferedReader br = new BufferedReader(isr);  
  14.                 String line = null;  
  15.                 System.out.println("<OUTPUT>");  
  16.                 while((line = br.readLine())!=null){  
  17.                         System.out.println(line);  
  18.                         System.out.println("</OUTPUT>");  
  19.                         int exitValue = p.waitFor();  
  20.                         System.out.println("Process exitValue="+exitValue);  
  21.                 }  
  22.         }  
  23. }  
  24. //执行结果(在Ubuntu9.10下执行)  
  25. <OUTPUT>  
  26. class  CUtil.java  Exec.java  Exec_Javac.java  Exec_Output.java  Str.java  
  27. </OUTPUT>  
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader ;
import java.io.BufferedReader;
public class Exec_Output{
        public static void main(String []args)throws IOException,InterruptedException{
                Runtime rt = Runtime.getRuntime();
                Process p = rt.exec("dir");
                //int exitValue = p.exitValue();
                //int exitValue = p.waitFor();
                InputStream is = p.getInputStream();
                InputStreamReader isr = new InputStreamReader(is);
                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 exitValue = p.waitFor();
                        System.out.println("Process exitValue="+exitValue);
                }
        }
}
//执行结果(在Ubuntu9.10下执行)
<OUTPUT>
class  CUtil.java  Exec.java  Exec_Javac.java  Exec_Output.java  Str.java
</OUTPUT>


因为以上代码,我使用了Ubuntu9.10下执行,是一点问题都没有,但当我在windows xp下执行,意外却发生了。

E:classescomjavaworldjpitfallsarticle2>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)

也许大家觉得奇怪,其实我也很奇怪,为什么呢。好好在Linux下,咋到XP就有问题了呢。

以下引用了别人的话:

说实在的,这个错误还真是让我摸不着头脑,我觉得在windows中返回2应该是没有找到这个文件的缘故,可能windows 2000中只有cmd命令,dir命令不是当前环境变量能够解释的吧。我也不知道了,慢慢往下看吧。

嘿,果然和作者想的一样,就是因为dir命令是由windows中的解释器解释的,直接执行dir时无法找到 dir.exe这个命令,所以会出现文件未找到这个2的错误。如果我们要执行这样的命令,就要先根据操作系统的不同执行不同的解释程序 command.com 或者cmd.exe。


到这里,大家明白了吧。

因此,别人还作了一些改进:

Java代码   收藏代码
  1. import java.io.IOException;  
  2. import java.io.InputStream;  
  3. import java.io.InputStreamReader ;  
  4. import java.io.BufferedReader;  
  5. public class Exec_Output_Win{  
  6.         public static void main(String []args)throws IOException,InterruptedException{  
  7.                 if(args.length < 1){  
  8.                         System.out.println("USAGE:java Exec_Output_Win <cmd>");  
  9.                         System.exit(1);  
  10.                 }  
  11.                 try{  
  12.                         String osName = System.getProperty("os.name");  
  13.                         String []cmd = new String[3];  
  14.                         if(osName.equals("Windows NT")){  
  15.                                 cmd[0] = "cmd.exe";  
  16.                                 cmd[1] = "/C";  
  17.                                 cmd[2] = args[0];  
  18.                         }else if(osName.equals("Windows 95")){  
  19.                                 cmd[0] = "command.com";  
  20.                                 cmd[1] = "/C";  
  21.                                 cmd[2] = args[0];  
  22.                         }else if(osName.equals("Linux")){  
  23.                                 System.out.println("Os:"+osName);  
  24.                                 System.exit(0);  
  25.                         }  
  26.                         Runtime rt = Runtime.getRuntime();  
  27.                         System.out.println("Execing "+cmd[0]+" "+cmd[1]+" "+cmd[2]);  
  28.                         Process p = rt.exec(cmd);  
  29.                         //any error message?  
  30.                         StreamGobbler err = new StreamGobbler(p.getErrorStream(),"ERROR");  
  31.                         //any output?  
  32.                         StreamGobbler out= new StreamGobbler(p.getInputStream(),"OUTPUT");  
  33.                         //kick them off  
  34.                         err.start();  
  35.                         out.start();  
  36.                         //any error?  
  37.                         int exitValue = p.waitFor();  
  38.                         System.out.println("Process exitValue="+exitValue);  
  39.                 }catch(Exception e){  
  40.                         e.printStackTrace();  
  41.                 }  
  42.         }  
  43. }  
  44. class StreamGobbler extends Thread{  
  45.         InputStream is;  
  46.         String type;  
  47.         StreamGobbler(InputStream is,String type){  
  48.                 this.is = is;  
  49.                 this.type = type;  
  50.         }  
  51.         public void run(){  
  52.                 try{  
  53.                         InputStreamReader isr = new InputStreamReader(is);  
  54.                         BufferedReader br = new BufferedReader(isr);  
  55.                         String line = null;  
  56.                         while((line = br.readLine())!=null){  
  57.                                 System.out.println(type +">"+line);  
  58.                         }  
  59.                 }catch(IOException e){  
  60.                         e.printStackTrace();  
  61.                 }  
  62.         }  
  63. }  
  64. //执行结果:  
  65. (Linux 环境下)  
  66. Os:Linux  
  67. (windows XP环境下)  
  68. E:classescomjavaworldjpitfallsarticle2>java GoodWindowsExec "dir *.java"  
  69. Execing cmd.exe /C dir *.java  
  70. OUTPUT> Volume in drive E has no label.  
  71. OUTPUT> Volume Serial Number is 5C5F-0CC9  
  72. OUTPUT>  
  73. OUTPUT> Directory of E:classescomjavaworldjpitfallsarticle2  
  74. OUTPUT>  
  75. OUTPUT>10/23/00 09:01p 805 BadExecBrowser.java  
  76. OUTPUT>10/22/00 09:35a 770 BadExecBrowser1.java  
  77. OUTPUT>10/24/00 08:45p 488 BadExecJavac.java  
  78. OUTPUT>10/24/00 08:46p 519 BadExecJavac2.java  
  79. OUTPUT>10/24/00 09:13p 930 BadExecWinDir.java  
  80. OUTPUT>10/22/00 09:21a 2,282 BadURLPost.java  
  81. OUTPUT>10/22/00 09:20a 2,273 BadURLPost1.java  
  82. ... (some output omitted for brevity)  
  83. OUTPUT>10/12/00 09:29p 151 SuperFrame.java  
  84. OUTPUT>10/24/00 09:23p 1,814 TestExec.java  
  85. OUTPUT>10/09/00 05:47p 23,543 TestStringReplace.java  
  86. OUTPUT>10/12/00 08:55p 228 TopLevel.java  
  87. OUTPUT> 22 File(s) 46,661 bytes  
  88. OUTPUT> 19,678,420,992 bytes free  
  89. ExitValue: 0  
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader ;
import java.io.BufferedReader;
public class Exec_Output_Win{
        public static void main(String []args)throws IOException,InterruptedException{
                if(args.length < 1){
                        System.out.println("USAGE:java Exec_Output_Win <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];
                        }else if(osName.equals("Linux")){
                                System.out.println("Os:"+osName);
                                System.exit(0);
                        }
                        Runtime rt = Runtime.getRuntime();
                        System.out.println("Execing "+cmd[0]+" "+cmd[1]+" "+cmd[2]);
                        Process p = rt.exec(cmd);
                        //any error message?
                        StreamGobbler err = new StreamGobbler(p.getErrorStream(),"ERROR");
                        //any output?
                        StreamGobbler out= new StreamGobbler(p.getInputStream(),"OUTPUT");
                        //kick them off
                        err.start();
                        out.start();
                        //any error?
                        int exitValue = p.waitFor();
                        System.out.println("Process exitValue="+exitValue);
                }catch(Exception e){
                        e.printStackTrace();
                }
        }
}
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 e){
                        e.printStackTrace();
                }
        }
}
//执行结果:
(Linux 环境下)
Os:Linux
(windows XP环境下)
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


因为我在linux下运行,得不到想要的结果。

以下引用作者的话:

这里作者教了一个windows中很有用的方法,呵呵,至少我是不知道的,就是cmd.exe /C +一个windows中注册了后缀的文档名,windows会自动地调用相关的程序来打开这个文档,我试了一下,的确很好用,但是好像文件路径中有空格的话就有点问题,我加上引号也无法解决。

这里作者强调了一下,不要假设你执行的程序是可执行的程序,要清楚自己的程序是单独可执行的还是被解释的,本章的结束作者会介绍一个命令行工具来帮助我们分析。

这里还有一点,就是得到process的输出的方式是getInputStream,这是因为我们要从Java 程序的角度来看,外部程序的输出对于Java来说就是输入,反之亦然。

最后的一个漏洞的地方就是错误的认为exec方法会接受所有你在命令行或者Shell中输入并接受的字符串。这些错误主要出现在命令作为参数的情况下,程序员错误的将所有命令行中可以输入的参数命令加入到exec中(这段翻译的不好,凑合看吧)。下面的例子中就是一个程序员想重定向一个命令的输出。


Java代码   收藏代码
  1. import java.util.*;  
  2. import java.io.*;  
  3. // StreamGobbler omitted for brevity  
  4. public class BadWinRedirect  
  5. {  
  6. public static void main(String args[])  
  7. {  
  8. try  
  9. {  
  10. Runtime rt = Runtime.getRuntime();  
  11. Process proc = rt.exec("java jecho 'Hello World' > test.txt");  
  12. // any error message?  
  13. StreamGobbler errorGobbler = new  
  14. StreamGobbler(proc.getErrorStream(), "ERROR");  
  15. // any output?  
  16. StreamGobbler outputGobbler = new  
  17. StreamGobbler(proc.getInputStream(), "OUTPUT");  
  18. // kick them off  
  19. errorGobbler.start();  
  20. outputGobbler.start();  
  21. // any error???  
  22. int exitVal = proc.waitFor();  
  23. System.out.println("ExitValue: " + exitVal);  
  24. catch (Throwable t)  
  25. {  
  26. t.printStackTrace();  
  27. }  
  28. }  
  29. }  
  30. Running BadWinRedirect produces:  
  31.   
  32. E:classescomjavaworldjpitfallsarticle2>java BadWinRedirect  
  33. OUTPUT>'Hello World' > test.txt  
  34. ExitValue: 0  
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中的包。

Java代码   收藏代码
  1. import java.util.*;  
  2. import java.io.*;  
  3. class StreamGobbler extends Thread  
  4. {  
  5. InputStream is;  
  6. String type;  
  7. OutputStream os;  
  8. StreamGobbler(InputStream is, String type)  
  9. {  
  10. this(is, type, null);  
  11. }  
  12. StreamGobbler(InputStream is, String type, OutputStream redirect)  
  13. {  
  14. this.is = is;  
  15. this.type = type;  
  16. this.os = redirect;  
  17. }  
  18. public void run()  
  19. {  
  20. try  
  21. {  
  22. PrintWriter pw = null;  
  23. if (os != null)  
  24. pw = new PrintWriter(os);  
  25. InputStreamReader isr = new InputStreamReader(is);  
  26. BufferedReader br = new BufferedReader(isr);  
  27. String line=null;  
  28. while ( (line = br.readLine()) != null)  
  29. {  
  30. if (pw != null)  
  31. pw.println(line);  
  32. System.out.println(type + ">" + line);  
  33. }  
  34. if (pw != null)  
  35. pw.flush();  
  36. catch (IOException ioe)  
  37. {  
  38. ioe.printStackTrace();  
  39. }  
  40. }  
  41. }  
  42. public class GoodWinRedirect  
  43. {  
  44. public static void main(String args[])  
  45. {  
  46. if (args.length < 1)  
  47. {  
  48. System.out.println("USAGE java GoodWinRedirect <outputfile>");  
  49. System.exit(1);  
  50. }  
  51. try  
  52. {  
  53. FileOutputStream fos = new FileOutputStream(args[0]);  
  54. Runtime rt = Runtime.getRuntime();  
  55. Process proc = rt.exec("java jecho 'Hello World'");  
  56. // any error message?  
  57. StreamGobbler errorGobbler = new  
  58. StreamGobbler(proc.getErrorStream(), "ERROR");  
  59. // any output?  
  60. StreamGobbler outputGobbler = new  
  61. StreamGobbler(proc.getInputStream(), "OUTPUT", fos);  
  62. // kick them off  
  63. errorGobbler.start();  
  64. outputGobbler.start();  
  65. // any error???  
  66. int exitVal = proc.waitFor();  
  67. System.out.println("ExitValue: " + exitVal);  
  68. fos.flush();  
  69. fos.close();  
  70. catch (Throwable t)  
  71. {  
  72. t.printStackTrace();  
  73. }  
  74. }  
  75. }  
  76. Running GoodWinRedirect produces:  
  77.   
  78. E:classescomjavaworldjpitfallsarticle2>java GoodWinRedirect test.txt  
  79. OUTPUT>'Hello World'  
  80. ExitValue: 0  
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 <outputfile>");
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


这里就不多说了,看看就明白,紧接着作者给出了一个监测命令的小程序

Java代码   收藏代码
  1. import java.util.*;  
  2. import java.io.*;  
  3. // class StreamGobbler omitted for brevity  
  4. public class TestExec  
  5. {  
  6. public static void main(String args[])  
  7. {  
  8. if (args.length < 1)  
  9. {  
  10. System.out.println("USAGE: java TestExec "cmd"");  
  11. System.exit(1);  
  12. }  
  13. try  
  14. {  
  15. String cmd = args[0];  
  16. Runtime rt = Runtime.getRuntime();  
  17. Process proc = rt.exec(cmd);  
  18. // any error message?  
  19. StreamGobbler errorGobbler = new  
  20. StreamGobbler(proc.getErrorStream(), "ERR");  
  21. // any output?  
  22. StreamGobbler outputGobbler = new  
  23. StreamGobbler(proc.getInputStream(), "OUT");  
  24. // kick them off  
  25. errorGobbler.start();  
  26. outputGobbler.start();  
  27. // any error???  
  28. int exitVal = proc.waitFor();  
  29. System.out.println("ExitValue: " + exitVal);  
  30. catch (Throwable t)  
  31. {  
  32. t.printStackTrace();  
  33. }  
  34. }  
  35. }  
  36. //对这个程序进行运行:  
  37. E:classescomjavaworldjpitfallsarticle2>java TestExec "e:javadocsindex.html"  
  38. java.io.IOException: CreateProcess: e:javadocsindex.html error=193  
  39. at java.lang.Win32Process.create(Native Method)  
  40. at java.lang.Win32Process.<init>(Unknown Source)  
  41. at java.lang.Runtime.execInternal(Native Method)  
  42. at java.lang.Runtime.exec(Unknown Source)  
  43. at java.lang.Runtime.exec(Unknown Source)  
  44. at java.lang.Runtime.exec(Unknown Source)  
  45. at java.lang.Runtime.exec(Unknown Source)  
  46. at TestExec.main(TestExec.java:45)  
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.<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 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()。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值