2011-10-03 10 views
7

Ho bisogno di un metodo java che legga l'output del prompt dei comandi e lo memorizzi in una stringa da leggere in Java.Ottieni l'output del prompt dei comandi su String in Java

Questo è ciò che ho finora ma non funziona correttamente.

public void testGetOutput() { 
    System.out.println("\n\n****This is the testGetOutput Method!****"); 
    String s = null; 
    String query = "dir " + this.desktop; 
    try { 
     Runtime runtime = Runtime.getRuntime(); 
     InputStream input = runtime.exec("cmd /c " + query).getInputStream(); 
     BufferedInputStream buffer = new BufferedInputStream(input); 
     BufferedReader commandResult = new BufferedReader(new InputStreamReader(buffer)); 
     String line = ""; 
     try { 
      while ((line = commandResult.readLine()) != null) { 
       s += line + "\n"; 
      } 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
     System.out.println(s); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
}//end testGetOutput() 

Credo che il problema è quando provo a modificare la query di essere un comando che eseguirà HandBrakeCLI.exe. Guardando il mio sistema quando il programma è in esecuzione (ma sembra essersi fermato), mi mostra che HandBrakeCLI.exe è in esecuzione sotto una finestra cmd che viene eseguita sotto il mio IDE. Tutto ciò ha senso, ma il HandBrakeCLI.exe non esce, quindi suppongo che sia per questo che non riesco a leggere l'output come input per il mio programma.

Quindi, dopo quello sfondo. La mia grande domanda è questa: come posso ottenere che HandBrakeCLI.exe si chiuda dopo aver finito con la mia query in modo da poter ottenere il suo output? Solo per informazioni aggiuntive, l'unica differenza tra il metodo precedente e il metodo di scansione DVD che ho per HandBrakeCLI è la variabile di query è diversa. Come in questo esempio:

String query = "C:\Users\Kent\Desktop\HBCLI\HandBrakeCLI -t --scan -i "C:\Users\Kent\Desktop\General Conference DVDs\Sources\174th October 2004\DVD 1"; //this is actually a variable in the DVD object, but here's an example' 

Oh, e dal modo in cui, quando si esegue la query in un prompt dei comandi regolare, fa esattamente quello che voglio io, dandomi tutto l'output ho disperatamente voglio!

Ecco il problema originale (non sono sicuro di come inviare nuovamente una domanda):

ho cercato dappertutto e non possono capirlo. Non sono sicuro che quello che ho trovato sia rilevante anche per quello che voglio fare. Non ho ancora un bel po 'di codice per questo, quindi non farò molto per mettere il codice qui e penso che questo dovrebbe essere abbastanza semplice, quindi ho intenzione di dare alcuni screenshot qui. Quindi, ecco il mio compito:

  1. cartella Scan che è piena di cartelle DVD rippati (Video_TS cartelle con i file VOB, ecc) e memorizzare i nomi delle cartelle, come il titolo del DVD.

  2. Analizza ciascuna cartella utilizzando HandBrakeCLI e memorizza l'output in una stringa.

  3. Registra la stringa per identificare ciascun titolo, capitolo e lingua.

  4. generare query di restituire alla HandBrakeCLI per codificare massa ogni lingua in ogni capitolo di ogni titolo per ogni DVD (potete vedere il motivo per cui voglio automatizzare questo!)

  5. Conservare queste query in un *. bat file

L'unica parte di cui non sono sicuro è il passaggio 2! Posso fare tutto il resto abbastanza facilmente. Ho letto molto su OutputStreams, ma non riesco a capire come funziona. Ho davvero bisogno di ottenere l'output su una stringa che posso regex per ottenere le cose che mi servono.Ecco le schermate di ciò che serve per inserire e cosa devo striscia dall'uscita:

Input HandBrakeCLI:

enter image description here

output per la scansione:

enter image description here

risposta

5

In primo luogo è necessario un modo non-blocking per leggere da Standard.out e Standard.err

private class ProcessResultReader extends Thread 
{ 
    final InputStream is; 
    final String type; 
    final StringBuilder sb; 

    ProcessResultReader(@Nonnull final InputStream is, @Nonnull String type) 
    { 
     this.is = is; 
     this.type = type; 
     this.sb = new StringBuilder(); 
    } 

    public void run() 
    { 
     try 
     { 
      final InputStreamReader isr = new InputStreamReader(is); 
      final BufferedReader br = new BufferedReader(isr); 
      String line = null; 
      while ((line = br.readLine()) != null) 
      { 
       this.sb.append(line).append("\n"); 
      } 
     } 
     catch (final IOException ioe) 
     { 
      System.err.println(ioe.getMessage()); 
      throw new RuntimeException(ioe); 
     } 
    } 

    @Override 
    public String toString() 
    { 
     return this.sb.toString(); 
    } 
} 

Allora avete bisogno di legare questa classe nelle rispettive InputStream e OutputStream oggetti.

try 
    { 
     final Process p = Runtime.getRuntime().exec(String.format("cmd /c %s", query)); 
     final ProcessResultReader stderr = new ProcessResultReader(p.getErrorStream(), "STDERR"); 
     final ProcessResultReader stdout = new ProcessResultReader(p.getInputStream(), "STDOUT"); 
     stderr.start(); 
     stdout.start(); 
     final int exitValue = p.waitFor(); 
     if (exitValue == 0) 
     { 
      System.out.print(stdout.toString()); 
     } 
     else 
     { 
      System.err.print(stderr.toString()); 
     } 
    } 
    catch (final IOException e) 
    { 
     throw new RuntimeException(e); 
    } 
    catch (final InterruptedException e) 
    { 
     throw new RuntimeException(e); 
    } 

Questo è più o meno la piastra della caldaia che uso quando ho bisogno di qualcosa di Runtime.exec() in Java.

Un sistema più avanzato sarebbe usare FutureTask e Callable o almeno Runnable anziché estendentesi direttamente Thread che non è la migliore pratica.

NOTA:

I @Nonnull annotazioni sono nella biblioteca JSR305. Se stai usando Maven e stai usando Maven, aggiungi questa dipendenza al tuo pom.xml.

<dependency> 
    <groupId>com.google.code.findbugs</groupId> 
    <artifactId>jsr305</artifactId> 
    <version>1.3.9</version> 
</dependency> 
+0

Jarrod, grazie per la rapida risposta! Cercherò di implementarlo subito e farti sapere come va! – kentcdodds

+0

Perfetto! Non sono esattamente sicuro di come funzioni. Ma guarderò un po 'per capirlo. Ma sì, ha funzionato come un fascino! Ora devo solo regexare tutte queste cose! Comunque, grazie mille per il tuo aiuto! Oh, e non sono sicuro di cosa sia Maven. Il mio IDE è Netbeans. Non ho bisogno di aggiungere il materiale . Grazie ancora! – kentcdodds

1

Supponendo che tu usi Runtime.exec() per avviare il tuo processo esterno, dandoti un oggetto Process, ci sono tre metodi rilevanti su quell'oggetto: getOutputStream(), getInputStream() e getErrorStream().

Penso che sia facile essere confusi su questi - probabilmente stai pensando che vuoi vedere l'output del processo, quindi un "flusso di output" è quello che vuoi. Ma la cosa che devi ricordare è che la denominazione di questi oggetti è dal punto di vista del codice Java - un OutputStream è per Java a cui scrivere l'output, mentre un InputStream è per Java da cui leggere l'input. L'output del tuo processo esterno è, dal punto di vista di Java, input.

Quindi si utilizza getInputStream() e si chiama il metodo appropriato su InputStream restituito da esso per leggere l'output. Si consiglia inoltre di utilizzare getErrorStream() per garantire che non manchi nulla perché è stato scritto sull'errore standard.

+0

Grazie per il chiarimento! Questo è stato un po 'di confusione. Il problema che sto affrontando ora è invece di stampare i risultati della query (come si vede nel mio secondo screenshot), sta stampando la query stessa. C'è troppo contenuto nel codice da aggiungere a un commento qui, quindi ecco un link a un documento collabedit: http: // collabedit.it/5r384 – kentcdodds

+0

Un problema, penso, è che 'exec()' si aspetta un eseguibile reale - un file batch non è un programma eseguibile, è una serie di comandi che devono essere eseguiti dalla shell di Windows. Vedi http://stackoverflow.com/questions/615948/how-do-i-run-a-batch-file-from-my-java-application. –

+0

Ci stiamo avvicinando davvero! Quindi ora il mio problema è che il mio oggetto lettore buffer è null. Non sono sicuro del perché. Ho aggiornato il codice sul documento collabedit. Noterai che ho inserito println attorno al comandoResult perché è lì che il codice fa una pausa e commandResult.readLine() = null quando dovrebbe essere uguale alla prima linea di input (o almeno, è quello che sto cercando). Grazie ancora per l'aiuto! http://collabedit.com/5r384 – kentcdodds

5

Questo completo esempio di programma Java viene eseguito il comando 'dir' (elenco di directory) sulla riga di comando e tira il risultato in una stringa e lo stampa sulla console.

import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.InputStreamReader; 

public class X { 
    public static void main(String[] args) { 
     try{ 
      String command = "dir"; 
      String s = get_commandline_results(command); 
      System.out.println(s); 
     } 
     catch(Exception e){ 
      e.printStackTrace(); 
     } 
     System.out.println("done"); 
    } 

    public static String get_commandline_results(String cmd) 
     throws IOException, InterruptedException, IllegalCommandException{ 

     //Do not remove the authorizedCommand method. Be prepared 
     //to lose your hard drive if you have not white-listed the 
     //commands that can run. 
     if (!authorizedCommand(cmd)) 
      throw new IllegalCommandException(); 

     String result = ""; 
     final Process p = Runtime.getRuntime(). 
      exec(String.format("cmd /c %s", cmd)); 
     final ProcessResultReader stderr = new ProcessResultReader(
       p.getErrorStream(), "STDERR"); 
     final ProcessResultReader stdout = new ProcessResultReader(
       p.getInputStream(), "STDOUT"); 
     stderr.start(); 
     stdout.start(); 
     final int exitValue = p.waitFor(); 
     if (exitValue == 0){ 
      result = stdout.toString(); 
     } 
     else{ 
      result = stderr.toString(); 
     } 
     return result; 
    } 
    public static boolean authorizedCommand(String cmd){ 
     //Do not allow any command to be run except for the ones 
     //that we have pre-approved here. This lessens the 
     //likelihood that fat fingers will wreck your computer. 
     if (cmd.equals("dir")) 
      return true; 
     //add the commands you want to authorize here. 

     return false; 
    } 
} 

class ProcessResultReader extends Thread{ 
    final InputStream is; 
    final String type; 
    final StringBuilder sb; 

    ProcessResultReader(final InputStream is, String type){ 
     this.is = is; 
     this.type = type; 
     this.sb = new StringBuilder(); 
    } 

    public void run() 
    { 
     try{ 
      final InputStreamReader isr = new InputStreamReader(is); 
      final BufferedReader br = new BufferedReader(isr); 
      String line = null; 
      while ((line = br.readLine()) != null) 
      { 
       this.sb.append(line).append("\n"); 
      } 
     } 
     catch (final IOException ioe) 
     { 
      System.err.println(ioe.getMessage()); 
      throw new RuntimeException(ioe); 
     } 
    } 
    @Override 
    public String toString() 
    { 
     return this.sb.toString(); 
    } 
} 
class IllegalCommandException extends Exception{ 
    private static final long serialVersionUID = 1L; 
    public IllegalCommandException(){ } 
} 

In Windows, questo è il risultato che ottengo

Directory of D:\projects\eric\eclipseworkspace\testing2 
07/05/2012 01:06 PM <DIR>   . 
07/05/2012 01:06 PM <DIR>   .. 
06/05/2012 11:11 AM    301 .classpath 
06/05/2012 11:11 AM    384 .project 
06/05/2012 11:11 AM <DIR>   .settings 
07/05/2012 01:42 PM <DIR>   bin 
06/05/2012 11:11 AM <DIR>   src 
07/05/2012 01:06 PM    2,285 usernames.txt 
       3 File(s)   2,970 bytes 
       5 Dir(s) 45,884,035,072 bytes free 

done 
+0

+1 per pubblicare un'altra soluzione praticabile per le generazioni a venire. – kentcdodds