2012-10-22 28 views
10

Wykonuję polecenie, które zwraca mi numer wersji pliku; 'Nazwa pliku'. Ale jeśli wystąpi jakiś problem z wykonaniem polecenia, aplikacja się zawiesi. Co mogę zrobić, aby tego uniknąć? Poniżej mój kod.Runtime.getRuntime(). Exec (cmd) wiszące

String cmd= "cmd /C si viewhistory --fields=revision --project="+fileName; 
Process p = Runtime.getRuntime().exec(cmd) ; 
BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream())); 
String line = null; 
while ((line = in.readLine()) != null) { 
System.out.println(line); 
} 

} catch (Exception e) { 
e.printStackTrace(); 
} 
+2

Zobacz [ProcessBuilder] (http://docs.oracle.com/javase/7/docs/api/java/lang/ProcessBuilder.html). To jest prostsze API do robienia tego rodzaju rzeczy. – RNJ

+0

Jeśli nie ma wyjścia, 'readLine' będzie blokować na zawsze. – assylias

+0

@assylias: jak sprawdzić, czy nie ma wyjścia? – user1688404

Odpowiedz

24

Zgadnij, problem polega na tym, że czytasz tylko InputStream i nie czyta ErrorStream. Musisz także uważać, aby oba strumienie były odczytywane równolegle. Może się zdarzyć, że obecnie dane przesyłane ze strumienia wyjściowego wypełniają bufor systemu operacyjnego, polecenie exec zostanie automatycznie zawieszone, aby dać czytelnikowi szansę na opróżnienie bufora. Ale program nadal będzie czekał na przetworzenie wyjścia. W związku z tym zawiesza się.

Można utworzyć oddzielną klasę do obsługi zarówno wejście i błędów Stream następująco,

public class ReadStream implements Runnable { 
    String name; 
    InputStream is; 
    Thread thread;  
    public ReadStream(String name, InputStream is) { 
     this.name = name; 
     this.is = is; 
    }  
    public void start() { 
     thread = new Thread (this); 
     thread.start(); 
    }  
    public void run() { 
     try { 
      InputStreamReader isr = new InputStreamReader (is); 
      BufferedReader br = new BufferedReader (isr); 
      while (true) { 
       String s = br.readLine(); 
       if (s == null) break; 
       System.out.println ("[" + name + "] " + s); 
      } 
      is.close();  
     } catch (Exception ex) { 
      System.out.println ("Problem reading stream " + name + "... :" + ex); 
      ex.printStackTrace(); 
     } 
    } 
} 

Sposób korzystania jest następująca,

String cmd= "cmd /C si viewhistory --fields=revision --project="+fileName; 
Process p = Runtime.getRuntime().exec(cmd) ; 
s1 = new ReadStream("stdin", p.getInputStream()); 
s2 = new ReadStream("stderr", p.getErrorStream()); 
s1.start(); 
s2.start(); 
p.waitFor();   
} catch (Exception e) { 
e.printStackTrace(); 
} finally { 
    if(p != null) 
     p.destroy(); 
} 
+0

to jest co najmniej idealne dla mnie! dzięki –

+1

Tak, ten blok kodu również uratuje mnie przed ignorancją hehe :) – Akyo

+0

Niezwykle pomocna dziękuję! – welterw8

3

Kod ten jest oparty na sam pomysł Arhama, ale jest zaimplementowany za pomocą równoległego strumienia java 8, co czyni go trochę bardziej zwięzłym.

public static String getOutputFromProgram(String program) throws IOException { 
    Process proc = Runtime.getRuntime().exec(program); 
    return Stream.of(proc.getErrorStream(), proc.getInputStream()).parallel().map((InputStream isForOutput) -> { 
     StringBuilder output = new StringBuilder(); 
     try (BufferedReader br = new BufferedReader(new InputStreamReader(isForOutput))) { 
      String line; 
      while ((line = br.readLine()) != null) { 
       output.append(line); 
       output.append("\n"); 
      } 
     } catch (IOException e) { 
      throw new RuntimeException(e); 
     } 
     return output; 
    }).collect(Collectors.joining()); 
} 

można wywołać metodę jak to

getOutputFromProgram("cmd /C si viewhistory --fields=revision --project="+fileName); 

pamiętać, że ta metoda będzie powiesić jeśli program dzwonisz zawiesza się, co się stanie, jeśli wymaga to wejście.

+0

Działa świetnie działające 'mvn verify' i nie owijam go' cmd/C' - czy wiesz jaka jest korzyść z zawijania drugiej powłoki? –

+1

Skopiowałem dokładnie ciąg polecenia OP i zaczęło się od "cmd/C". Nie sądzę, że w tym przypadku można go zawijać. – mikeyreilly