来自 apache-commons exec 的 Process output

我的智慧在这里结束。我相信这很简单,我很可能在对java和流的理解上有很大的漏洞。我认为有太多的类,以至于我有点不知所措,试图通过API来弄清楚我何时以及如何使用大量的输入/输出流。

我刚刚了解到apache commons库的存在(自学Java失败),目前正在尝试转换我的一些Run runtime.getRuntime().exec以使用commons - exec。它已经修复了一些每6个月一次的问题,然后消失的风格问题与exec。

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

调用代码位于摇摆工人内部。

我迷路了 如何使用泵StreamHandler...无论如何,这是旧代码:

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”?),将其放入缓冲读取器中,然后在那里循环,直到缓冲区为空。

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

无论如何,我试图使用commons exec获得相同的行为,基本上再次从谷歌找到的代码中:

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/err 中的字节填充我提供给它的 OutputStream?

如果是这样,您将如何获得上述行为以使其逐行流式传输输出?在示例中,人们显示您在末尾调用out.toString(),我假设这只会在脚本完成运行后为我提供所有输出的转储?您将如何做到这一点,以便在它逐行运行时显示输出?

------------未来编辑---------------------

通过谷歌找到这个,效果也很好:

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());
}

答案 1

不要将 a 传递给 ,请使用抽象类 的实现。来自 javadocByteArrayOutputStreamPumpStreamHandlerorg.apache.commons.exec.LogOutputStream

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

因此,LogOutputStram正在预处理输出,以便您控制处理单个行而不是原始字节。像这样:

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;
    }
}

然后,在阻止调用您的之后,您将获得您正在寻找的标准和标准错误。从仅执行流程并将所有 stdOut/stdErr 收集到行列表中的角度来看,它是可选的。exec.executegetLines()ExecutionResultHandler


答案 2

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

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

泵流量处理器

文档

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


推荐