2011-12-21 3 views
19

я могу запустить эту команду из командной строки без каких-либо проблем (сценарий проверки выполняется):Java Runtime.exec()

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, если я уйду от параметра URL и просто сделать:

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!"); 
    } 
    } 
+0

Возможно, текущий каталог имеет значение? Вы можете попробовать переключиться на другой каталог в командной строке. – Yogu

+0

вы должны проверить фактическую командную строку, которая выполняется с Java, на Linux - 'ps f', на Win - sysinternals ProcessExplorer –

+1

это может быть проблема ssl. можете ли вы попытаться вызвать конечную точку http, чтобы проверить ее? – phoet

ответ

17

Вам необходимо осушить вывода и ошибок потоков процесса, или же он будет блокировать, когда выполняется программа производит вывод.

Из Process documentation:

Поскольку некоторые местные платформы только обеспечивают ограниченный размер буфера для стандартных входных и выходных потоков, неспособность оперативно записать входной поток или читать выходной поток подпроцесса может вызвать подпроцесс к блок и даже тупик.

+0

Я не видел метод дренажа для процесса. Какой код я бы на самом деле выполнял? Я обновил вопрос с полным кодом. – user994165

+1

, чтобы слить выходные и потоки ошибок, просто выполните: InputStream in = ...; in.skip (in.available()); InputStream err = ...; err.skip (err.available()); –

+1

@ user994165 есть пример кода для слива потоков [здесь] (http://stackoverflow.com/a/7962434/523391) – prunge

7

Прочитать (и закрыть) p.getInputStream() и p.getErrorStream().

Например:

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

Что делать, если выход больше, чем память кучи Java? Хотя, я думаю, в большинстве случаев вы знаете, что этого не будет. Проблема может возникнуть, если вы напишете такой метод, а затем используйте его для чего-то, производящего большой результат после того, как вы забудете это ограничение. –

+0

@ EvgeniSergeev Правильно, читайте и закрывайте их по-другому, я просто упомянул их в качестве примера. –

7

Люди обычно попались на EXEC рутинных зависаний в Java. Я тоже это сообразил. Проблема в том, что процесс, который вы пытаетесь выполнить, может (в зависимости от множества вещей) сначала записывать в stdOut или stdErr. Если вы справитесь с ними в неправильном порядке, exec зависает. Чтобы правильно справляться с этим, вы должны создать 2 потока для чтения stdErr и stdOut одновременно. Sth like:

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(); 
+1

с использованием redirectErrorStream - гораздо лучшая идея: http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/ProcessBuilder.html#redirectErrorStream%28boolean%29 –

Смежные вопросы