`
geshenyi
  • 浏览: 100942 次
  • 性别: 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调用Linux命令

    ### Java调用Linux命令 Java提供了一种强大的机制来执行操作系统级别的任务,其中包括调用Linux命令。实现这一功能的核心是`Runtime`类中的`exec()`方法。这个方法允许Java应用程序创建一个新的进程来执行指定的...

    Java调用应用程序和Dos中的命令

    在Java编程中,有时候我们需要执行一些操作系统级别的任务,例如启动一个外部程序、执行一些系统命令等。这通常可以通过Java的`Runtime`类实现,尤其是通过`Runtime.exec()`方法来创建一个新的进程。本文将详细介绍...

    perl脚本调用练习和调用系统命令并展示输出信息

    标题 "perl脚本调用练习和调用系统命令并展示输出信息" 提示我们这篇内容主要涉及使用Perl脚本执行系统命令以及如何处理输出信息。Perl是一种强大的文本处理语言,常用于系统管理任务,包括调用其他系统工具或程序。...

    windows下java调用ffmpeg视频处理环境搭建

    Java提供了`Runtime.getRuntime().exec()`方法或`ProcessBuilder`类来执行系统命令。例如,我们可以使用以下Java代码来执行一个简单的FFmpeg命令: ```java String command = "ffmpeg -i input.mp4 output.mp4"; ...

    Java调用SPSS的实例

    Java调用SPSS的实例是将Java编程语言与统计分析软件SPSS(Statistical Product and Service Solutions)结合使用的典型应用。SPSS提供了Java接口,使得开发者可以利用Java代码执行SPSS的数据处理和分析任务,无需...

    exchange/powershell,Java调用powershell开通邮箱

    标题 "exchange/powershell,Java调用powershell开通邮箱" 暗示了这是一个关于使用Java编程语言调用PowerShell脚本在Exchange服务器上创建邮箱的教程或项目。Exchange是微软提供的一款企业级电子邮件服务器软件,而...

    java调用视频转换工具ffmpeg.zip

    在Java中调用FFmpeg,通常有两种方式:直接执行系统命令和使用Java库。直接执行命令是通过Runtime.exec()方法或ProcessBuilder类来调用FFmpeg的命令行工具,例如: ```java String command = "ffmpeg -i input.mp4 ...

    java调用R语言源码

    3. **Rscript**: Java可以通过`Runtime.getRuntime().exec()`方法执行系统命令,调用R脚本并捕获输出。这种方法简单,但不适合复杂的交互式任务,因为每次调用都会启动新的R进程。 4. **rJava**: rJava是R的一个...

    java调用spss实例

    Java调用SPSS实例主要涉及的是如何通过编程方式与SPSS进行交互,这在数据分析、自动化报告或构建数据处理系统时非常有用。SPSS(Statistical Product and Service Solutions)是一款强大的统计分析软件,而它的Java...

    java调用本地浏览器的demo

    Java调用本地浏览器的示例,通常涉及到Java与操作系统交互的能力,这主要通过Java的`Runtime`类或者`ProcessBuilder`类实现。这两个类允许Java程序执行系统命令,例如打开一个本地已安装的浏览器来加载特定的URL。...

    java中调用本地exe文件

    通过本文的学习,我们了解到了如何在Java中调用本地exe文件的基本原理、常见应用场景以及具体的代码实现细节。掌握这些技能对于开发人员来说是非常有用的,可以帮助我们更好地利用Java与操作系统之间的交互能力。

    非常好用java调用c++ dll文件demo

    Java调用C++ DLL文件是跨语言编程中的一个重要应用场景,特别是在既有Java代码库又有C++动态链接库的情况下。本文将详细讲解如何在Java程序中调用C++编写的DLL文件,以及一个可用的示例。 首先,理解Java与C++交互...

    java调用python脚本

    例如,"Java调用Python脚本"是一个常见的需求,特别是在数据处理、科学计算或机器学习等场景中,Python的强大库可以与Java的稳定性和企业级应用能力相结合。本教程将详细讲解如何在Java程序中调用Python脚本。 首先...

    java调用shell脚本

    在Java编程中,有时我们需要与操作系统进行交互,执行一些系统级别的任务,比如调用Shell脚本。这在处理自动化任务、远程服务器管理或系统集成时非常常见。在给定的资源中,我们可以看到如何在Java中实现这个功能,...

    用java调用python

    这是原生 Java 提供的方法,通过执行系统命令来运行 Python 脚本。例如,你可以创建一个 `ProcessBuilder` 实例,指定 Python 解释器和脚本路径,然后启动进程。这种方法简单,但效率较低,且不适用于复杂的交互式...

    MAC下java调用opencv包含opencv_454.jar和libopencv_java454.dylib

    在Mac环境下,使用Java调用OpenCV库是一个常见的需求,特别是在计算机视觉和图像处理的项目中。OpenCV是一个强大的开源库,提供了丰富的功能,用于图像处理、计算机视觉算法以及机器学习。本文将详细介绍如何在Mac上...

    windows下java调用ffmpeg视频处理源码

    6. **环境搭建**:配合"windows下java调用ffmpeg视频处理环境搭建",这部分可能包括如何在Windows系统上安装FFmpeg,设置环境变量,以及如何确保Java程序能正确找到并执行FFmpeg的可执行文件。 7. **错误处理和日志...

    JAVA执行shell命令小工具

    这两个类提供了运行外部进程的能力,从而允许Java程序调用系统命令。 在给定的描述中,虽然没有提供具体的信息,但我们可以推测这篇博文可能是博主Qindongliang分享的一个实用工具,可能包括如何在Java代码中构建和...

    java 调用 mplayer

    Java中的`Runtime.getRuntime().exec()`方法允许我们执行系统命令,这就为我们提供了与Mplayer交互的途径。通过构建命令字符串,我们可以启动Mplayer、传递参数(如文件路径)以及执行播放控制操作。 1. **进程管理...

Global site tag (gtag.js) - Google Analytics