【问题标题】:Java Runtime.exec()Java 运行时.exec()
【发布时间】:2012-01-25 14:45:23
【问题描述】:

我可以毫无问题地从命令行运行这个命令(验证脚本执行):

c:/Python27/python ../feedvalidator/feedvalidator/src/demo.py https://das.dynalias.org:8080/das_core/das/2.16.840.1.113883.4.349/1012581676V377802/otherAdminData/careCoordinators 

如果我不使用 URL 参数并从 java 中执行以下操作:

String[] args1 = {"c:/Python27/python", "../feedvalidator/feedvalidator/src/demo.py" };
Runtime r = Runtime.getRuntime();
Process p = r.exec(args1);

它工作正常。如果我使用某些 URL 作为参数,例如:

String[] args1 = {"c:/Python27/python", "../feedvalidator/feedvalidator/src/demo.py" , "http://www.intertwingly.net/blog/index.atom"};
// or 
String[] args1 = {"c:/Python27/python", "../feedvalidator/feedvalidator/src/demo.py" , "http://www.cnn.com"};

它也可以正常工作。

但是如果我使用这个特定的 URL https://das.dynalias.org:8080/das_core/das/2.16.840.1.113883.4.349/1012581676V377802/otherAdminData/careCoordinators,那么脚本就会挂起(java 等待进程完成)。我不确定为什么它可以从该 URL 的命令行运行,但不能从 java 程序运行。我尝试在 URL 参数周围添加引号,但这也不起作用。我在 URL 中没有看到任何我认为需要转义的字符。

完整代码:

String urlToValidate = "https://das.dynalias.org:8080/das_core/das/2.16.840.1.113883.4.349/1012581676V377802/otherAdminData/careCoordinators";

String[] args1 = {"c:/Python27/python", "C:/Documents and Settings/vhaiswcaldej/DAS_Workspace/feedvalidator/feedvalidator/src/demo.py", urlToValidate };
System.out.println(args1[0] + " " + args1[1] + " " + args1[2]);

Runtime r = Runtime.getRuntime();
Process p = r.exec(args1);
BufferedReader br = new BufferedReader(new InputStreamReader(
p.getInputStream()));
int returnCode = p.waitFor();
 System.out.println("Python Script or OS Return Code: " + Integer.toString(returnCode));
if (returnCode >= 2) {
    .out.println("OS Error: Unable to Find File or other OS error.");
    }

String line = "";
while (br.ready()) {
     String str = br.readLine();
     System.out.println(str);
     if (str.startsWith("line")) {
     //TODO: Report this error back to test tool.
     //System.out.println("Error!");
     }
     }

【问题讨论】:

  • 也许当前目录很重要?您可以尝试在命令行中切换到另一个目录。
  • 您应该检查从 Java 执行的实际命令行,在 Linux - ps f,在 Win - sysinternals ProcessExplorer
  • 这可能是一些 ssl 问题。你可以尝试调用一个http端点来验证它吗?
  • 你是在创建进程后调用Process的p.waitFor()方法吗? exec 应该是非阻塞的,因此如果没有调用 waitFor,您可能会在代码的其他地方锁定,因为创建的进程尚未完成执行
  • 试试用双引号,比如String[] args1 = {"c:/Python27/python", "../feedvalidator/feedvalidator/src/demo.py" , "\"https://das.dynalias.org:8080/das_core/das/2.16.840.1.113883.4.349/1012581676V377802/otherAdminData/careCoordinators\""};

标签: java


【解决方案1】:

人们通常会被 Java 中的 exec 例程挂起。我也被那个咳嗽了一次。问题是您尝试执行的进程可能(取决于很多事情)首先写入stdOut或stdErr。如果您以错误的顺序处理它们,exec 将挂起。要始终正确处理此问题,您必须创建 2 个线程来同时读取 stdErr 和 stdOut。某样东西:

Process proc = Runtime.getRuntime().exec( cmd );

// handle process' stdout stream
Thread out = new StreamHandlerThread( stdOut, proc.getInputStream() );
out.start();

// handle process' stderr stream
Thread err = new StreamHandlerThread( stdErr, proc.getErrorStream() );
err.start();

exitVal = proc.waitFor(); // InterruptedException

...

out.join();
err.join();

【讨论】:

【解决方案2】:

阅读(并关闭)p.getInputStream()p.getErrorStream()

例如:

// com.google.common.io.CharStreams
CharStreams.toString(new InputStreamReader(p.getInputStream()));
CharStreams.toString(new InputStreamReader(p.getErrorStream()));

【讨论】:

  • 如果输出大于 Java 的堆内存怎么办?虽然我猜在大多数情况下你知道它不会。如果您编写这样的方法,然后在忘记此限制后将其用于产生大量输出的东西上,则可能会出现问题。
  • @EvgeniSergeev 没错,用另一种方式阅读并关闭它们,我只是以它们为例。
【解决方案3】:

你需要把进程的输出和错误流排干,否则当执行的程序产生输出时它会阻塞。

来自Process documentation

由于部分原生平台只为标准输入输出流提供有限的缓冲区大小,未能及时写入子进程的输入流或读取输出流可能会导致子进程阻塞,甚至死锁。

【讨论】:

  • 我没有看到该过程的排水方法。我将实际运行什么代码?我已经用完整的代码更新了这个问题。
  • 排空输出和错误流,只需这样做: InputStream in = ...; in.skip(in.available());输入流错误 = ...; err.skip(err.available());
  • @user994165 有用于排出流的示例代码here
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-28
  • 2014-08-15
相关资源
最近更新 更多