我正在编写一个程序来从文件中读取命令,执行它们并打印每个命令的结果。
这是我的: 导入 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 可以解决第二个命令)
我做错了什么?
编辑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/