简体   繁体   English

Java 进程获取 output 并设置超时

[英]Java Process get output and set timeout

How can I obtain a process' output while setting a timeout value?如何在设置超时值时获取进程的 output?

I am currently using apache commons io utils to create a String from the process' standard and error outputs.我目前正在使用 apache commons io 实用程序从进程的标准和错误输出创建字符串。

The code below, as is (with the comments), works fine for processes that terminate.下面的代码(与注释一样)适用于终止的进程。 However, if the process doesn't terminate, the main thread doesn't terminate either!但是,如果进程没有终止,主线程也不会终止!

If I uncomment out the commented code and instead comment out process.waitfor(), the method will properly destroy non terminating processes.如果我取消注释掉注释的代码,而是注释掉 process.waitfor(),该方法将正确地破坏非终止进程。 However, for terminating processes, the output isn't properly obtained.但是,对于终止进程,无法正确获取 output。 It appears that once waitfor() is completed, I cannot get the process' input and error streams?似乎一旦 waitfor() 完成,我就无法获取进程的输入和错误流?

Finally, if I attempt to move the commented section to where process.waitfor() currently is, remove process.waitfor() and uncomment the commented section, then for non terminating processes, the main thread also won't stop.最后,如果我尝试将注释部分移动到 process.waitfor() 当前所在的位置,删除 process.waitfor() 并取消注释注释部分,那么对于非终止进程,主线程也不会停止。 This is because the process.waitfor(15, ...) will never be reached.这是因为 process.waitfor(15, ...) 永远不会到达。

private static Outputs runProcess(String command) throws Exception {
    Process process = Runtime.getRuntime().exec(command);

    // if (!process.waitFor(15, TimeUnit.SECONDS)) {
    // System.out.println("Destroy");
    // process.destroy();
    // }

    // Run and collect the results from the standard output and error output
    String stdStr = IOUtils.toString(process.getInputStream());
    String errStr = IOUtils.toString(process.getErrorStream());

    process.waitFor();

    return new Outputs(stdStr, errStr);
}

As @EJP suggested, You can use different threads to capture the streams or use ProcessBuilder or redirect to a file from your command. 正如@EJP建议的那样,您可以使用不同的线程来捕获流或使用ProcessBuilder或从命令重定向到文件。
Here are 3 approaches that I feel you can use. 我认为您可以使用以下3种方法。

  1. Using different threads for Streams. 对Stream使用不同的线程。

     Process process = Runtime.getRuntime().exec("cat "); ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(2); Future<String> output = newFixedThreadPool.submit(() -> { return IOUtils.toString(process.getInputStream()); }); Future<String> error = newFixedThreadPool.submit(() -> { return IOUtils.toString(process.getErrorStream()); }); newFixedThreadPool.shutdown(); // process.waitFor(); if (!process.waitFor(3, TimeUnit.SECONDS)) { System.out.println("Destroy"); process.destroy(); } System.out.println(output.get()); System.out.println(error.get()); 
  2. Using ProcessBuilder 使用 ProcessBuilder

     ProcessBuilder processBuilder = new ProcessBuilder("cat") .redirectError(new File("error")) .redirectOutput(new File("output")); Process process = processBuilder.start(); // process.waitFor(); if (!process.waitFor(3, TimeUnit.SECONDS)) { System.out.println("Destroy"); process.destroy(); } System.out.println(FileUtils.readFileToString(new File("output"))); System.out.println(FileUtils.readFileToString(new File("error"))); 
  3. Use a redirection operator in your command to redirect Output & Error to a file and then Read from File. 在命令中使用重定向运算符将“输出和错误”重定向到文件,然后从文件读取。

Here is very good blog which explains different ways of handling Runtime.Exec 是一个很好的博客,它解释了处理Runtime.Exec不同方法。

This is a slightly adjusted version of Kishore Bandi's first solution which uses separate thread to capture output.这是Kishore Bandi 的第一个解决方案的略微调整版本,它使用单独的线程来捕获 output。

It has been simplified, uses no external libraries and have more robust termination code.它已被简化,不使用外部库并具有更健壮的终止代码。

Process process = new ProcessBuilder("cat", "file.txt")
    .redirectErrorStream(true)
    .start();

ExecutorService pool = Executors.newFixedThreadPool(1);
Future<String> output = pool.submit(() -> new String(process.getInputStream().readAllBytes()));
pool.shutdown();

if (!process.waitFor(5, TimeUnit.SECONDS)) {
    process.destroyForcibly();
    process.waitFor(1, TimeUnit.SECONDS);
    output.cancel(true); // If destroy didn't word the stream doesn't close
}

try {
    System.out.println("Output:\n" + output.get(0, TimeUnit.SECONDS));
} catch (ExecutionException | TimeoutException e) {
    System.out.println("No output");
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM