`
hellsing42
  • 浏览: 261750 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

StreamGobbler的详细解释

阅读更多
这是摘自《More Java pitfalls 中文版》上的例子。

先请编译和运行下面程序:
import java.util.*; 
import java.io.*; 

public class BadExecJavac2 
{ 
    public static void main(String args[]) 
    { 
        try 
        {             
            Runtime rt = Runtime.getRuntime(); 
            Process proc = rt.exec("javac"); 
            int exitVal = proc.waitFor(); 
            System.out.println("Process exitValue: " + exitVal); 
        } catch (Throwable t){ 
            t.printStackTrace(); 
        } 
    } 
}   



我们知道javac命令,当不带参数运行javac 程序时,它将输出帮助说明,为什么上面程序不产生任何输出并挂起,永不完成呢?java文档上说,由于有些本地平台为标准输入和输出流所提供的缓冲区大小有限,如果不能及时写入子进程的输入流或者读取子进程的输出流,可能导致子进程阻塞,甚至陷入死锁。所以,上面的程序应改写为:
import java.util.*; 
import java.io.*; 

public class MediocreExecJavac 
{ 
    public static void main(String args[]) 
    { 
        try 
        {             
            Runtime rt = Runtime.getRuntime(); 
            Process proc = rt.exec("javac"); 
            InputStream stderr = proc.getErrorStream(); 
            InputStreamReader isr = new InputStreamReader(stderr); 
            BufferedReader br = new BufferedReader(isr); 
            String line = null; 
            System.out.println("<ERROR>"); 
            while ( (line = br.readLine()) != null) 
                System.out.println(line); 
            System.out.println("</ERROR>"); 
            int exitVal = proc.waitFor(); 
            System.out.println("Process exitValue: " + exitVal); 
        } catch (Throwable t){ 
            t.printStackTrace(); 
        } 
    } 
} 




下面是正确的输出:

D:\java>java   MediocreExecJavac
<ERROR>
Usage: javac <options> <source files>
where possible options include:
  -g                         Generate all debugging info
  -g:none                    Generate no debugging info
  -g:{lines,vars,source}     Generate only some debugging info
  -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
  -cp <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
  -endorseddirs <dirs>       Override location of endorsed standards path
  -d <directory>             Specify where to place generated class files
  -encoding <encoding>       Specify character encoding used by source files
  -source <release>          Provide source compatibility with specified release

  -target <release>          Generate class files for specific VM version
  -version                   Version information
  -help                      Print a synopsis of standard options
  -X                         Print a synopsis of nonstandard options
  -J<flag>                   Pass <flag> directly to the runtime system

</ERROR>
Process exitValue: 2

D:\java>


下面是一个更一般的程序,它用两个线程同步清空标准错误流和标准输出流,并能根据你所使用的windows操作系统选择windows命令解释器command.com或cmd.exe,然后执行你提供的命令。


import java.util.*; 
import java.io.*; 

class StreamGobbler extends Thread 
{ 
    InputStream is; 
    String type;  //输出流的类型ERROR或OUTPUT 
     
    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); 
                System.out.flush(); 
            } 
            } catch (IOException ioe) 
              { 
                ioe.printStackTrace();   
              } 
    } 
} 

public class GoodWindowsExec 
{ 
    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" ); 
            System.out.println("osName: " + osName); 
            String[] cmd = new String[3]; 

            if(osName.equals("Windows XP") ||osName.equals("Windows 2000")) 
            { 
                cmd[0] = "cmd.exe" ; 
                cmd[1] = "/C" ; 
                cmd[2] = args[0]; 
            } 
            else if( osName.equals( "Windows 98" ) ) 
            { 
                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? 
            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(); 
        } 
    } 
} 





下面是一个测试结果:

D:\java>java  GoodWindowsExec "copy Test.java Test1.java"
osName: Windows XP
Execing cmd.exe /C copy Test.java Test1.java
OUTPUT>已复制         1 个文件。
ExitValue: 0

D:\java>

下面的测试都能通过(windows xp+jdk1.5)

D:\java>java   GoodWindowsExec dir

D:\java>java   GoodWindowsExec Test.java

D:\java>java   GoodWindowsExec regedit.exe

D:\java>java   GoodWindowsExec NOTEPAD.EXE

D:\java>java   GoodWindowsExec first.ppt

D:\java>java   GoodWindowsExec second.doc


以上的意思是说如果不使用StreamGobbler把inputstream清空的话,就会造成进程被堵死,从而导致waitFor()一直等下去,永远结束不了.所以StreamGobbler作为单独的线程会自动清理inputstream防止他被堵住
分享到:
评论

相关推荐

    StreamGobbler.java

    StreamGobbler.java

    org.apache.commons.net.ftp*实现FTP下载

    利用org.apache.commons.net.ftp.*实现FTP批量下载,包括子目录文件

    ProcessRunner.zip

    StreamGobbler errorGobbler = new StreamGobbler(errorStream, "ERROR"); errorGobbler.start(); ``` 3. **设置环境变量和工作目录**:通过`ProcessBuilder`的`environment()`和`directory()`方法设置必要的...

    JAVA实现PDF转HTML

    在IT行业中,PDF(Portable Document Format)是一种广泛用于存储和分发文档的格式,而HTML(HyperText Markup Language)则是互联网上网页的标准内容结构语言。... ...Java中有很多库可以帮助我们完成这项任务,如PDFBox...

    Java代码执行shell命令的实现

    下面将详细介绍Java代码执行shell命令的实现方法。 环境准备 在执行shell命令之前,需要获取JVM底层操作系统的信息,并定义通用消费流的类。为了获取操作系统的信息,可以使用`System.getProperty("os.name")`方法...

    java应用程序远程登录linux并执行其命令

    根据给定的信息,本文将详细解释如何通过Java应用程序实现对Linux服务器的远程登录,并执行相应的命令。本案例中,我们采用的是Ganymed SSH2库来实现这一功能。 ### 一、Ganymed SSH2 库简介 Ganymed SSH2 是一个...

    java在win下启动bat和在linux下启动shell脚本

    `RunScript.java`和`StreamGobbler.java`这两个文件可能就是用来实现这个功能的。 `RunScript.java`很可能是主类,它包含了一个方法来判断当前运行的操作系统,并根据系统类型来执行相应的脚本。在Windows中,...

    java执行Linux命令的方法

    StreamGobbler outputGobbler = new StreamGobbler(process.getInputStream(), "Output"); errorGobbler.start(); outputGobbler.start(); // ... } ``` `Runtime.exec()`方法有几点需要注意: 1. **确保在...

    oracle如何使用java source调用外部程序

    下面我们将详细讲解如何操作。 首先,我们创建一个名为`jv_run_extpro`的Java源代码,其主要目的是通过`Runtime.getRuntime().exec(cmd)`方法执行系统命令。在这个Java类中,定义了一个`run`方法,该方法接收一个...

    ssh协议依赖jar包:ganymed-ssh2-build

    SSH(Secure Shell)协议是一种网络协议,用于在不安全的网络上提供安全的远程登录和其他服务。在Java环境中,开发人员通常使用库来实现SSH功能,其中一个常用的库就是Ganymed SSH-2。这个库名为ganymed-ssh2-build...

    StartStopAppium:关于如何以编程方式启动停止 appium 服务器的代码示例

    本文将详细介绍如何使用Java编程语言来启动和停止Appium服务器,这对于自动化测试流程的管理和控制至关重要。 首先,我们需要理解Appium的基本概念。Appium是一个基于WebDriver协议的自动化测试工具,它支持iOS、...

    scp操作大全

    - `-v`:详细模式,显示执行的详细过程。 - `-c`:启用压缩。 - `-i`:指定私钥文件用于身份验证。 3. **基本操作示例**: - **从本地到远程**: ``` scp localfile user@remotehost:remotedir/ scp -r ...

    java执行bat命令碰到的阻塞问题的解决方法

    因此,修改后的代码在执行bat命令时,不仅创建了bat进程,还同时启动了两个`StreamGobbler`线程,分别处理错误流和标准输出流,确保bat命令的输出能够被及时消费,从而避免了阻塞问题。 总的来说,解决Java执行bat...

    JAVA 转换字符编码工具

    - `StreamGobbler.java`:可能是用来处理输入流的类,可能包含从输入流中读取数据并进行编码转换的功能。 - `BufferedStream01.java`:可能实现了使用缓冲流进行文件读写的例子,可能涉及到字符编码转换。 - `...

    Java应用程序远程登录linux并执行其命令.pdf

    下面我们将详细介绍Java应用程序远程登录Linux并执行命令的实现原理和实践。 _ssh协议和Java实现_ SSH(Secure Shell)是一种安全的远程登录协议,用于在网络上进行加密的连接和通信。Java可以通过使用SSH客户端库...

    ssh2向linux发送操作命令,ftp下载linux文件到本地

    - 读取命令输出,通常使用 `StreamGobbler` 类来读取标准输出流和错误输出流。 ### 2. FTP 文件传输 #### 2.1 FTP 协议简介 FTP(File Transfer Protocol)是一种用于在网络上进行文件传输的标准协议。它支持...

    pdf转html.rar

    2. `StreamGobbler.java`:这个名字暗示这可能是一个用于处理I/O流的辅助类,特别是处理命令行进程的输出流。在PDF转HTML过程中,如果使用了命令行工具,那么这个类可能用来捕获并处理子进程的输出,例如标准输出和...

    ganymed-ssh2-build210.jar java远程访问linux服务器操作、上传下载文件

    import ch.ethz.ssh2.StreamGobbler; import common.Logger; import org.apache.commons.lang.StringUtils; import java.io.*; import java.util.logging.Level; /** * SCP远程访问Linux服务器读取文件 * User: ...

    Java远程调用Shell脚本并获取输出信息【推荐】

    InputStream stdout = new StreamGobbler(session.getStdout()); BufferedReader br = new BufferedReader(new InputStreamReader(stdout)); ``` 五、关闭Session和Connection 最后,关闭Session和Connection: `...

Global site tag (gtag.js) - Google Analytics