2012-10-22 16 views
10

Ich führe einen Befehl aus, der mir die Revisionsnummer einer Datei zurückgibt; 'Dateiname'. Wenn jedoch ein Problem beim Ausführen des Befehls auftritt, legt die Anwendung auf. Was kann ich tun, um diesen Zustand zu vermeiden? Hier finden Sie meinen Code.Runtime.getRuntime(). Exec (cmd) hängt

+2

Werfen Sie einen Blick auf [ProcessBuilder] (http://docs.oracle.com/javase/7/docs/api/java/lang/ProcessBuilder.html). Dies ist eine einfachere API für solche Dinge. – RNJ

+0

Wenn es keine Ausgabe gibt, wird 'readLine' für immer blockieren. – assylias

+0

@assylias: Wie überprüfe ich, ob es keine Ausgabe gibt? – user1688404

Antwort

24

Ich vermute, das Problem ist, dass Sie nur InputStream lesen und ErrorStream nicht lesen. Sie müssen auch darauf achten, dass beide Streams parallel gelesen werden. Es kann vorkommen, dass die Daten, die aus dem Ausgabedatenstrom gepiped werden, den Betriebssystempuffer füllen. Ihr exec-Befehl wird automatisch ausgesetzt, um Ihrem Leser die Möglichkeit zu geben, den Puffer zu leeren. Das Programm wartet jedoch immer noch auf die Verarbeitung des Ausgangs. Daher tritt der Hang auf.

Sie können eine eigene Klasse erstellen sowohl Stream als die Eingabe und Fehler zu handhaben wie folgt

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(); 
     } 
    } 
} 

Die Art und Weise Sie es wie folgt verwenden ist,

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

das ist perfekt für mich! danke –

+1

Yep, dass Block von Code auch rette mich vor ignorant hehe :) – Akyo

+0

Extrem hilfreich danke! – welterw8

3

Dieser Code auf die basiert Die gleiche Idee, Arham's Antwort, aber wird mit einem Java 8 parallelen Strom implementiert, was es ein wenig prägnanter macht.

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()); 
} 

können Sie rufen die Methode, wie diese

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

Beachten Sie, dass diese Methode hängen wird, wenn das Programm, das Sie hängt fordern, was passieren wird, wenn es eine Eingabe erfordert.

+0

Works great running 'mvn verify' und ich verpacke es nicht mit' cmd/C' - weißt du, was der Vorteil einer zweiten Shell ist? –

+1

Ich habe die Befehlszeichenfolge des OPs genau kopiert und sie hat mit "cmd/C" begonnen. Ich glaube nicht, dass es einen Vorteil bringt, es in diesem Fall zu verpacken. – mikeyreilly

Verwandte Themen