`
geshenyi
  • 浏览: 98202 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

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

    博客分类:
  • J2SE
阅读更多
学习了两篇的Runtime类,现在对它有了更深一层的了解,那么我们来看看下面的代码:
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。


到这里,大家明白了吧。

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

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中(这段翻译的不好,凑合看吧)。下面的例子中就是一个程序员想重定向一个命令的输出。


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中的包。

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


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

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()。

以上引用了很多别人的例子同原文。

分享到:
评论

相关推荐

    JAVA上百实例源码以及开源项目源代码

     用JAVA开发的一个小型的目录监视系统,系统会每5秒自动扫描一次需要监视的目录,可以用来监视目录中文件大小及文件增减数目的变化。 Java日期选择控件完整源代码 14个目标文件 内容索引:JAVA源码,系统相关,日历,...

    125集专攻JAVA基础 JAVA零基础入门学习视频教程 动力节点JAVA视频教程.txt

    北京动力节点-Java编程零基础教程-013-Java语言概述-Java的三个平台.mp4 北京动力节点-Java编程零基础教程-014-Java语言概述-JDK的下载与版本号.mp4 北京动力节点-Java编程零基础教程-015-Java语言概述-JDK的安装...

    Java开发技术大全(500个源代码).

    getLinePara.java 获取命令行参数示例 hasStaticMethod.java 静态成员方法示例 hasStatMember.java 静态成员变量示例 HelloNative.c 用C写的一个小程序 HelloNative.dll 用C生成的DLL文件 HelloNative.exp 用...

    JAVA上百实例源码以及开源项目

     用JAVA开发的一个小型的目录监视系统,系统会每5秒自动扫描一次需要监视的目录,可以用来监视目录中文件大小及文件增减数目的变化。 Java日期选择控件完整源代码 14个目标文件 内容索引:JAVA源码,系统相关,日历,...

    java中各种环境变量的配置

    我们先给系统配置一个JAVA_HOME的环境变量(目的是为了方便我们修改jdk的版本和第三方软件的调用).JAVA_HOME设为jdk的安装目录,如:D:\jdk1.6.0_21 2. 然后我们在为path配上jdk,设为%JAVA_HOME%\bin; classpath的...

    java图书馆swing源码-rcaller:用于调用R的Java库

    使用调用顺序命令功能,性能不会因为单个外部进程而丢失。 尽管 R 是单线程的,但 Java 中的多个 RCaller 实例可以创建和处理多个 R 进程。 基于 Servlet 的应用程序可以实例化许多 RCaller 对象,也可以通过使用...

    java内部学习笔记.docx

    2.14 Java系统API方法调用 14 2.15二进制基础 14 2.16 Java基础其他注意事项 14 面向对象 16 3.1类 16 3.2对象 16 3.3包 16 3.4方法及其调用 17 3.5引用 17 3.6访问控制(封装) 17 3.7构造器 17 3.8 super()、super...

    java 编程入门思考

    第10章 Java IO系统 10.1 输入和输出 10.1.1 InputStream的类型 10.1.2 OutputStream的类型 10.2 增添属性和有用的接口 10.2.1 通过FilterInputStream从InputStream里读入数据 10.2.2 通过FilterOutputStream向...

    Java初学者入门教学

    第10章 Java IO系统 10.1 输入和输出 10.1.1 InputStream的类型 10.1.2 OutputStream的类型 10.2 增添属性和有用的接口 10.2.1 通过FilterInputStream从InputStream里读入数据 10.2.2 通过FilterOutputStream向...

    疯狂JAVA讲义

    学生提问:老师,我想学习Java编程,到底是学习Eclipse好呢,还是学习JBuilder好呢? 21 1.9 本章小结 22 本章练习 22 第2章 理解面向对象 23 2.1 面向对象 24 2.1.1 结构化程序设计简介 24 2.1.2 程序的三种...

    java联想(中文)

    第10章 Java IO系统 10.1 输入和输出 10.1.1 InputStream的类型 10.1.2 OutputStream的类型 10.2 增添属性和有用的接口 10.2.1 通过FilterInputStream从InputStream里读入数据 10.2.2 通过FilterOutputStream向...

    JAVA_Thinking in Java

    第10章 Java IO系统 10.1 输入和输出 10.1.1 InputStream的类型 10.1.2 OutputStream的类型 10.2 增添属性和有用的接口 10.2.1 通过FilterInputStream从InputStream里读入数据 10.2.2 通过FilterOutputStream向...

    java初学者必看

    最近正在学习Java,也买了很多的有关Java方面的书籍,其中发现《跟我学Java》这本书,都的很不错啊,所以顺便拿电脑把这本书的目录敲了下来,与大家分享。尤其是那些和我一样初学Java的朋友们,看看哪一节对你有用,...

    Thinking in Java简体中文(全)

    第10章 Java IO系统 10.1 输入和输出 10.1.1 InputStream的类型 10.1.2 OutputStream的类型 10.2 增添属性和有用的接口 10.2.1 通过FilterInputStream从InputStream里读入数据 10.2.2 通过FilterOutputStream向...

    AIC的Java课程1-6章

     使用javac, java, appletviewer等命令编译和运行application和applet。 第2章 面向过程(变量和控制结构) 4课时  掌握变量的内存概念,8种基本类型,字面值和赋值。  正确使用各种Java...

    《C 语言实现 Linux Shell 命令解释器》项目.zip

    软件开发设计:应用软件开发、系统软件开发、移动应用开发、网站开发C++、Java、python、web、C#等语言的项目开发与学习资料 硬件与设备:单片机、EDA、proteus、RTOS、包括计算机硬件、服务器、网络设备、存储设备...

    基于Mysql+Java的进销存信息管理系统源码+sql数据库+项目说明.zip

    数据库的备份用到了mysql的mysqldump,调用了cmd命令执行mysqldump.exe 3.图片 【说明】 1、项目源码在上传前,都经过本地成功运行,功能测试无误。请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机...

    Java基于Netty实现的高性能分布式IM即时通信系统源码+项目说明.tar

    Java基于Netty实现的高性能分布式IM即时通信系统源码+项目说明.tar 介绍 `RIM`是基于Netty实现的面相开发者的高性能分布式即时通信系统,保证消息的实时性、有序性、可靠性。 ## 技术栈 | 名称 | 作用 | | -------...

    Thinking in Java 中文第四版+习题答案

    第10章 Java IO系统 10.1 输入和输出 10.1.1 InputStream的类型 10.1.2 OutputStream的类型 10.2 增添属性和有用的接口 10.2.1 通过FilterInputStream从InputStream里读入数据 10.2.2 通过FilterOutputStream向...

Global site tag (gtag.js) - Google Analytics