我想从我的Scala程序中运行多个外部命令,并能够处理它们的输出(发送到stdout)。有办法让我做到吗?程序的输出将包含一些日志记录以及可能的进度信息。我需要解析它们的输出并将其发送到数据库服务器,以保存日志,进度和关闭过程(如果它们返回错误)。重要的一点是,我不想等待不同的过程完成,而要连续获取输出。
我通过这种方式运行单独的外部命令:
def execCommand(command: String, bId: Long): Future[(Long, Stream[String])] = {
Future {
bId -> command.lineStream
}(executionContext)
}
“ bId”只是我的进程ID。除了使用以下方法之外,我无法管理其他方法:
Await.result()
方法,基于“ execCommand”方法的结果,但这不是我想要的方法。
我希望我的程序能够处理多个线程中的多个数据流,并连续地管理这些数据。不必是scala,用java解决方案也可以。
答案 0 :(得分:0)
启动该进程时,还将启动一个线程以读取该进程的输出。
如果要在单个线程中管理该输出,请创建一个BlockingQueue
并将输出发送到队列。您可能想跟踪输出来自哪个进程,因此在队列中使用POJO。
示例
public class CommandOutput {
private final int process;
private final String line;
public CommandOutput(int process, String line) {
this.process = process;
this.line = line;
}
public int getProcess() {
return this.process;
}
public String getLine() {
return this.line;
}
}
public class CommandOutputStreamHandler extends Thread {
private final int process;
private final InputStream stream;
private final BlockingQueue<CommandOutput> queue;
public CommandOutputStreamHandler(int process, InputStream stream, BlockingQueue<CommandOutput> queue) {
this.process = process;
this.stream = stream;
this.queue = queue;
}
@Override
public void run() {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(this.stream))) {
for (String line; (line = reader.readLine()) != null; ) {
this.queue.add(new CommandOutput(this.process, line));
Thread.sleep(200); // just for simulating output over time
}
} catch (Exception e) {
throw new RuntimeException(e); // or simply log the exception
} finally {
this.queue.add(new CommandOutput(this.process, null));
}
}
}
BlockingQueue<CommandOutput> queue = new LinkedBlockingQueue<>();
final int PROCS = 3;
for (int i = 0; i < PROCS; i++) {
Process p = new ProcessBuilder("cmd.exe", "/c", "dir", "/b")
.redirectErrorStream(true)
.start();
new CommandOutputStreamHandler(i, p.getInputStream(), queue)
.start();
}
for (int endMarkers = 0; endMarkers < PROCS; ) {
CommandOutput co = queue.take();
if (co.getLine() == null) {
endMarkers++;
} else {
System.out.println(co.getProcess() + ": " + co.getLine());
}
}
示例输出
0: .classpath
0: .project
1: .classpath
0: .settings
1: .project
0: lib
1: .settings
0: pom.xml
1: lib
0: src
1: pom.xml
0: target
1: src
2: .classpath
1: target
2: .project
2: .settings
2: lib
2: pom.xml
2: src
2: target