使用InputStream从外部程序读取Java标准输出

4

我正在尝试开发一个类,用于读取外部程序的标准输出(使用Process实例,Runtime.getRuntime().exec(cmdLine, env, dir))。 该程序在过程中需要用户输入,并且只有在输入有效时才会继续进行;这似乎导致我尝试读取其输出时出现了问题:

    egm.execute(); // run external the program with specified arguments
    BufferedInputStream stdout = new BufferedInputStream(egm.getInputStream());
    BufferedInputStream stderr = new BufferedInputStream(egm.getErrorStream());
    BufferedOutputStream stdin = new BufferedOutputStream(egm.getOutputStream());



    int c; //standard output input stream
    int e; //standadr error input stream

    while((c=stdout.read()) != -1) //<-- the Java class stops here, waiting for input? 
    {
        egm.processStdOutStream((char)c); 
    }
    while((e=stderr.read()) != -1)
    {
        egm.processStdErrStream((char)e);
    }
    //...

我该如何修复程序,以便接受有效输入并继续运行? 希望能帮忙解决这个问题!
5个回答

7
你需要同时消耗程序的标准输出和标准错误流以避免阻塞情况。请参见此文章,特别注意StreamGobbler机制,它可以在单独的线程中捕获stdout/err。这是防止阻塞的关键,如果不正确地执行会导致许多错误!

2
在这种情况下,您应该使用单独的线程读取InputStream和ErrStream。
此外,您可能希望执行以下操作:
public void run() {
  while( iShouldStillBeRunning ) {
       int c;
       while( stdout.available() > 0 && ((c=stdout.read()) != -1)) {
         egm.processStdOutStream((char)c);
       }

     Thread.sleep(100);
  }
}

因为在没有输入的情况下,stdout.read()会被阻塞。

1

首先,如果它正在写入错误流并且已经耗尽了缓冲区,那么这可能会阻塞-您在输出流完全完成之前不会从错误流中读取。

其次,您说它在过程中接受用户输入-您是否通过写入stdin提供任何用户输入?如果它正在等待输入,您应该适当地写入并刷新stdin


0
为了让其他人寻找这类问题的解决方案,我想补充一下,我遇到了一个非常类似的问题。但在我的情况下,程序还在等待单行输入。因此需要三个线程来异步处理所有三个通道。
如果不写入输出(即执行程序的标准输入),则会导致无法完全捕获输入(即执行程序的输出)。写入它会挂起进程。
解决方案是Jon Skeet提出的三个词:“并刷新它”。添加刷新后,没有挂起。谢谢!

0

在你的问题中,你没有说出当你尝试运行它时实际发生了什么。请更新并详细描述发生了什么以及你希望发生什么。如果告诉我们命令是什么,将会得到额外的加分。

此外,这是UNIX/Linux还是Windows?如果这是UNIX/Linux(或其他POSIX平台),由于安全原因,程序可能会在/dev/console而不是/dev/stdin上寻找输入。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接