java - ProcessBuilder 处理输出

标签 java process io

我正在编写一个程序来从文件中读取命令,执行它们并打印每个命令的结果。

这是我的: 导入 java.io.*;

public class StatsGenerator {
    public static void main(String [] args) throws IOException {
        ProcessBuilder builder = new ProcessBuilder( "/bin/bash" );
        Process p = builder.start();

        // get output from the process
        InputStream is = p.getInputStream();
        InputStreamReader isr = new InputStreamReader(is);
        BufferedReader processOutput = new BufferedReader(isr);

        InputStream errorStream = p.getErrorStream();
        InputStreamReader inputStreamReader = new InputStreamReader(errorStream);
        BufferedReader processErrorOutput = new BufferedReader(inputStreamReader);

        // get input to the process
        BufferedWriter processInput = new BufferedWriter(new OutputStreamWriter(p.getOutputStream()));

        // get commands to execute
        File f = new File("commands.txt");
        FileReader fileReader = new FileReader(f);
        BufferedReader commandsReader = new BufferedReader(fileReader);
        String command, output;
        while((command = commandsReader.readLine()) != null) {
            System.out.printf("Output of running %s is:\n", command);
            processInput.write(command);
            processInput.newLine();
            processInput.flush();
            while (processErrorOutput.ready() && (output = processErrorOutput.readLine()) != null) {
                System.out.println(output);
            }
            while ((output = processOutput.readLine()) != null) {
                System.out.println(output);
            }
        }

        // close process
        processInput.write("exit");
        processInput.newLine();
        processInput.flush();

        // close streams
        commandsReader.close();
        processErrorOutput.close();
        processInput.close();
        processOutput.close();

    }
}

命令.txt

java Solve problems/problem01.txt
java Solve problems/problem02.txt
java Solve problems/problem03.txt

然而,这会运行并输出第一个命令的结果,但会卡在第二个命令上...(而且我知道 Solve 可以解决第二个命令)

enter image description here

我做错了什么?

编辑1:

原来图片中的“Exception in thread 'main'”错误是由于我按了 CMD+C。这仍然没有解释为什么它停止输出。

最佳答案

我在这里看到的问题是您创建了一个运行 shell 的进程(OK),获取该进程的输入和输出流(OK),从文件中读取命令(OK)并将其提供给过程(确定)。然后您继续读取输出行,这会在第一个 Java 程序执行并产生输出时成功。

然后

while ((output = processOutput.readLine()) != null) { ...

阻塞,因为既没有另一行也没有 EOF。

您可以通过生成一个线程来读取和打印 processOutput 来解决这个问题。

另一种选择(我非常喜欢)是为每个命令创建一个进程。据我所知,您甚至不需要 shell:您可以立即执行 java SolveProblem ...。 (Unices 是为高效的子进程创建而构建的,并且不要认为 shell 会做不同的事情,所以没有额外的开销需要担心。)

在没有 shell 的情况下调用 java 的两个提示:确保使用完整路径名并将命令行拆分为标记。

编辑 在这里,只需使用 String[] 而不是包含命令的文本文件。

for( String cmd: new String[]{ "java Y aaa", "java Y bbb","java Y ccc" } ){
     String[] toks = cmd.split( "\\s" );
     ProcessBuilder builder = new ProcessBuilder( toks );
     Process p = builder.start();

     // get output from the process
     InputStream is = p.getInputStream();
     InputStreamReader isr = new InputStreamReader(is);
     BufferedReader processOutput = new BufferedReader(isr);

     InputStream errorStream = p.getErrorStream();
     InputStreamReader inputStreamReader = new InputStreamReader(errorStream);
     BufferedReader processErrorOutput = new BufferedReader(inputStreamReader);
     System.out.println("Executing " + cmd);
     String output;
     while( processErrorOutput.ready() &&
        (output = processErrorOutput.readLine()) != null) {
     System.out.println(output);
     }
     while ((output = processOutput.readLine()) != null) {
     System.out.println(output);
     }
     processErrorOutput.close();
     processOutput.close();
}

输出(愚蠢的 Y 打印参数 3 次):

Executing java Y aaa
1aaa
2aaa
3aaa
Executing java Y bbb
1bbb
2bbb
3bbb
Executing java Y ccc
1ccc
2ccc
3ccc

Another Edit If a marker line is inserted into the process output and the read loop checks the lines for this marker, the program can be used as it is (except for some corrections for closing processInput):

processInput.write(command + "; echo xxxEOFxxx");
//...
while ((output = processOutput.readLine()) != null
       && ! "xxxEOFxxx".equals(output)) {
    System.out.println(output);
}

虽然我不喜欢以这种方式使用“魔术字符串”,但在这里可能是允许的,因为您知道程序 Solve 的输出行集。

关于java - ProcessBuilder 处理输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33741856/

相关文章:

c# - InvalidOperationException 与进程

ios - 使用 GCD 复制文件的最有效方法?

java - java.io 中装饰流的限制是什么?

c - 在某些平台上向文件写入字节会被交换

java - Log4j2:日志堆栈跟踪没有异常

java - 重新排序 XML 标签

java - 使用 OkHttp 在 PHP 服务器上上传文件,出错?

python - 有没有办法使用 Perl 或 Python 检索进程统计信息?

c - 使用 execl 复制调用可执行文件时提供的两个文件

java - 如何使用 Gson 序列化 Optional<T> 类?