首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >apache-commons exec的进程输出

apache-commons exec的进程输出
EN

Stack Overflow用户
提问于 2011-09-08 04:57:34
回答 4查看 24.2K关注 0票数 29

我在这里束手无策。我确信这是一件简单的事情,我对java和stream的理解很可能有很大的漏洞。我认为有如此多的类,以至于我试图通过API来弄清楚何时以及如何使用大量的输入/输出流,这让我有点不知所措。

我刚刚了解到apache commons库的存在(自学java失败),目前正在尝试将我的一些Runtime.getRuntime().exec转换为使用commons - exec。它已经修复了一些每6个月出现一次的问题,然后用exec解决了一些风格问题。

该代码执行一个perl脚本,并在运行时在GUI中显示脚本中的stdout。

调用代码位于swingworker内部。

我不知道如何使用pumpStreamHandler...无论如何,下面是旧代码:

代码语言:javascript
复制
String pl_cmd = "perl script.pl"
Process p_pl = Runtime.getRuntime().exec( pl_cmd );

BufferedReader br_pl = new BufferedReader( new InputStreamReader( p_pl.getInputStream() ) );

stdout = br_pl.readLine();
while ( stdout != null )
{
    output.displayln( stdout );
    stdout = br_pl.readLine();
}

我想这就是我很久以前并不完全理解的复制粘贴代码。我假设上面的代码正在执行进程,然后获取输出流(通过"getInputStream"?),将其放入一个缓冲的读取器中,然后在那里循环,直到缓冲区为空。

我不明白的是,为什么这里不需要“waitfor”风格的命令?有没有可能会有一段时间,缓冲区将是空的,退出循环,并在进程仍在运行时继续进行?当我运行它时,情况似乎并非如此。

无论如何,我正在尝试使用commons exec获得相同的行为,基本上也是从google found代码开始:

代码语言:javascript
复制
DefaultExecuteResultHandler rh = new DefaultExecuteResultHandler();
ExecuteWatchdog wd  = new ExecuteWatchdog( ExecuteWatchdog.INFINITE_TIMEOUT );
Executor exec = new DefaultExecutor();

ByteArrayOutputStream out = new ByteArrayOutputStream();
PumpStreamHandler psh = new PumpStreamHandler( out );

exec.setStreamHandler( psh );
exec.setWatchdog( wd );

exec.execute(cmd, rh );
rh.waitFor();

我正在尝试弄清楚处理程序在做什么。我假设这将从exec对象获取输出,并用来自perl脚本的stdout/ OutputStream?

如果是这样的话,您将如何获得上述行为,使其逐行传输输出?在示例中,人们向我展示了在结束时调用out.toString(),我认为这只会在脚本运行完成后给我一个转储脚本的所有输出?您将如何使其显示逐行运行的输出?

这是通过google找到的,而且效果也很好:

代码语言:javascript
复制
public static void main(String a[]) throws Exception
{
    ByteArrayOutputStream stdout = new ByteArrayOutputStream();
    PumpStreamHandler psh = new PumpStreamHandler(stdout);
    CommandLine cl = CommandLine.parse("ls -al");
    DefaultExecutor exec = new DefaultExecutor();
    exec.setStreamHandler(psh);
    exec.execute(cl);
    System.out.println(stdout.toString());
}
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2012-09-06 21:30:34

不要将ByteArrayOutputStream传递给PumpStreamHandler,使用抽象类org.apache.commons.exec.LogOutputStream的实现。来自the javadoc

该实现解析传入的数据以构造一行,并将完整的行传递给用户定义的实现。

因此,LogOutputStram对输出进行预处理,使您可以控制处理单个行,而不是原始字节。如下所示:

代码语言:javascript
复制
import java.util.LinkedList;
import java.util.List;
import org.apache.commons.exec.LogOutputStream;

public class CollectingLogOutputStream extends LogOutputStream {
    private final List<String> lines = new LinkedList<String>();
    @Override protected void processLine(String line, int level) {
        lines.add(line);
    }   
    public List<String> getLines() {
        return lines;
    }
}

然后,在对exec.execute的阻塞调用之后,您的getLines()将获得您正在寻找的标准输出和标准错误。从仅执行进程的角度来看,ExecutionResultHandler是可选的,并将所有stdOut/stdErr收集到一个行列表中。

票数 31
EN

Stack Overflow用户

发布于 2011-09-08 05:09:51

我不明白的是,为什么这里不需要‘

’风格的命令?有没有可能会有一段时间,缓冲区将是空的,退出循环,并在进程仍在运行时继续进行?当我运行它时,情况似乎并非如此。

readLine块。也就是说,您的代码将等待,直到一行被读取。

PumpStreamHandler

来自Documentation

将子进程的标准输出和错误复制到父进程的标准输出和错误中。如果输出或错误流设置为null,则来自该流的任何反馈都将丢失。

票数 3
EN

Stack Overflow用户

发布于 2014-07-31 18:22:25

根据James A Wilson的回答,我创建了助手类"Execute“。它将他的答案封装到一个解决方案中,为了方便起见,该解决方案还提供了exitValue。

以这种方式执行命令需要一行:

ExecResult result=Execute.execCmd(cmd,expectedExitCode);

下面的Junit测试用例测试并展示了如何使用它:

Junit4测试用例:

代码语言:javascript
复制
package com.bitplan.newsletter;

import static org.junit.Assert.*;

import java.util.List;

import org.junit.Test;

import com.bitplan.cmd.Execute;
import com.bitplan.cmd.Execute.ExecResult;

/**
 * test case for the execute class
 * @author wf
 *
 */
public class TestExecute {
     @Test
   public void testExecute() throws Exception {
     String cmd="/bin/ls";
     ExecResult result = Execute.execCmd(cmd,0);
     assertEquals(0,result.getExitCode());
     List<String> lines = result.getLines();
     assertTrue(lines.size()>0);
     for (String line:lines) {
         System.out.println(line);
     }
   }
}

执行Java助手类:

代码语言:javascript
复制
package com.bitplan.cmd;

import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;

import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.LogOutputStream;
import org.apache.commons.exec.PumpStreamHandler;

/**
 * Execute helper using apache commons exed
 *
 *  add this dependency to your pom.xml:
   <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-exec</artifactId>
            <version>1.2</version>
        </dependency>

 * @author wf
 *
 */
public class Execute {

    protected static java.util.logging.Logger LOGGER = java.util.logging.Logger
            .getLogger("com.bitplan.cmd");

    protected final static boolean debug=true;

    /**
     * LogOutputStream
     * http://stackoverflow.com/questions/7340452/process-output-from
     * -apache-commons-exec
     * 
     * @author wf
     * 
     */
    public static class ExecResult extends LogOutputStream {
        private int exitCode;
        /**
         * @return the exitCode
         */
        public int getExitCode() {
            return exitCode;
        }

        /**
         * @param exitCode the exitCode to set
         */
        public void setExitCode(int exitCode) {
            this.exitCode = exitCode;
        }

        private final List<String> lines = new LinkedList<String>();

        @Override
        protected void processLine(String line, int level) {
            lines.add(line);
        }

        public List<String> getLines() {
            return lines;
        }
    }

    /**
     * execute the given command
     * @param cmd - the command 
     * @param exitValue - the expected exit Value
     * @return the output as lines and exit Code
     * @throws Exception
     */
    public static ExecResult execCmd(String cmd, int exitValue) throws Exception {
        if (debug)
            LOGGER.log(Level.INFO,"running "+cmd);
        CommandLine commandLine = CommandLine.parse(cmd);
        DefaultExecutor executor = new DefaultExecutor();
        executor.setExitValue(exitValue);
        ExecResult result =new ExecResult();
        executor.setStreamHandler(new PumpStreamHandler(result));
        result.setExitCode(executor.execute(commandLine));
        return result;
    }

}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7340452

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档