使用Java运行外部命令时出现错误流阻塞

Error stream blocking when running external command with Java

在SEAndroid上工作时,我从Java应用程序调用Setools命令。
它可以与小型SEAndroid策略完美配合,现在我需要使用真实的工具测试我的工具
SEAndroid政策。但不幸的是,我遇到了错误流问题。

这是我用来调用外部命令的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public static BufferedReader runCommand(final String[] args)
            throws IOException {

    BufferedReader stdInput = null;
    BufferedReader stdError = null;
    try {
        Process p = Runtime.getRuntime().exec(args);

        stdInput = new BufferedReader(new
                InputStreamReader(p.getInputStream()));

        stdError = new BufferedReader(new
                InputStreamReader(p.getErrorStream()));

        // read any errors from the attempted command
        String s = null;
        StringBuilder err = new StringBuilder();

        while ((s = stdError.readLine()) != null) {
            err.append(s +"
"
);
        }
        if (err.length() != 0) {
            throw new IOException(err.toString());
        }

        return stdInput;
    } finally {
        if (stdError != null) {
            stdError.close();
        }
    }
}

因此,如您所见,我调用了一个外部命令。然后读取错误流,如果有任何错误,则引发异常,否则我将返回InputStream,以便稍后进行解析。

使用真正的SEAndroid策略,错误流似乎被阻止(即使我读取了一个字符),并且无法解析命令的结果。如果我不读取任何内容就关闭了错误流,则该??应用程序可以正常运行,但是我想处理任何错误。
如果我在控制台中键入命令,它也可以正常工作。

在第一种情况下(使用小型SEAndroid策略),命令的输出很小(?350行)。
在第二种情况下(使用真实的SEAndroid策略),命令的输出较大(> 1500行)。

输出流的大小可能会影响错误流吗?这两个流是两个独特的资源,不是吗?
我不立即阅读输出流的事实很重要吗?

我担心这不是一个"编程"问题,而是一个系统问题。

有什么建议吗?

预先感谢您的帮助=)

编辑:

我尝试在错误流之前读取输出流,并且它可以正常工作。但是我需要在对输出流执行任何解析之前检查错误流,因此问题仍然很普遍。


首先,最好使用较新的ProcessBuilder类,而不是Runtime exec。如果您想更进一步,甚至可以使用Apache commons-exec来为您处理流处理和其他事情。

接下来,您已经发现,过程控制在Java中是一件棘手的事情,并且您已经遇到了它的棘手问题之一。从Java的Process类的文档中:

The parent process uses these streams to feed input to and get output from the subprocess. Because some native platforms only provide limited buffer size for standard input and output streams, failure to promptly write the input stream or read the output stream of the subprocess may cause the subprocess to block, and even deadlock.

您需要同时消耗(错误和输出)流,或者冒死锁的风险-这些都应在各自的线程上读取。使用类似StreamGobbler的东西(在Google上搜索,有很多东西)将是一个很好的步骤,或者如果您愿意,也可以自己动手。做到这一点并不难,但是如果您不熟悉多线程,则可能需要查看其他人的实现或采用Apache commons-exec路线。


输出的处理太烦人了,以至于我写了一个名为jproc的小库来处理消耗stdout和stderr的问题。它可以像这样通过外部程序简单地过滤字符串:

1
ProcBuilder.filter("x y z","sed" ,"s/y/a/")

它还允许您指定完成超时,并将非零退出代码转换为异常。