您的位置:首页 > 编程语言 > Java开发

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

2016-02-25 11:02 513 查看
学习了两篇的Runtime类,现在对它有了更深一层的了解,那么我们来看看下面的代码:

Java代码




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>

[java] view
plain copy

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代码




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

[java] view
plain copy

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代码




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

[java] view
plain copy

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代码




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] view
plain copy

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代码




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)

[java] view
plain copy

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()。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: