2013-06-13 23 views
7

Ho il seguente file di finestre batch (run.bat):Come uscita di processo I tubi in un file su Windows e JDK 6u45

@echo off 
echo hello batch file to sysout 

E il seguente codice Java, che gestisce i file batch e reindirizzamenti output in un file:

public static void main(String[] args) throws IOException { 
    System.out.println("Current java version is: " + System.getProperty("java.version")); 

    ProcessBuilder pb = 
      new ProcessBuilder("cmd.exe", "/c", 
        "run.bat" 
        ,">>", "stdout.txt","2>>", "stderr.txt" 
        ); 
    System.out.println("Command is: " + pb.command()); 

    Process proc = pb.start(); 

    InputStream in = proc.getInputStream(); 
    BufferedReader reader = new BufferedReader(new InputStreamReader(in)); 

    String line = null; 
    while ((line = reader.readLine()) != null) { 
     System.out.println(line); 
    } 

    int exitValue = proc.exitValue(); 
    System.out.println("Exit value: " + exitValue); 
} 

On JDK fino al JDK6u43 ottengo il seguente output:

Current java version is: 1.6.0_29 
Command is: [cmd.exe, /c, run.bat, >>, stdout.txt, 2>>, stderr.txt] 
Exit value: 0 

e l'output dello script è scritto nel file. Come di JDK 6u45 e 7, ottengo il seguente output:

Current java version is: 1.6.0_45 
Command is: [cmd.exe, /c, run.bat, >>, stdout.txt, 2>>, stderr.txt] 
hello batch file to sysout 
Exit value: 0 

E nulla è scritto nel file di output.

Questo può o non può essere messa in relazione alle modifiche apportate a Runtime.exec(), descritto in: http://www.oracle.com/technetwork/java/javase/6u45-relnotes-1932876.html

Qual è il modo corretto di iniziare un processo in Windows con uscita reindirizzato al file?

Nota: In uno scenario del mondo reale, il comando da eseguire può includere parametri con spazi, come in:

ProcessBuilder pb = new ProcessBuilder("cmd.exe", "/c", 
"run.bat", "Some Input With Spaces", 
">>", "stdout.txt","2>>", "stderr.txt"); 
+0

Aiuta a combinare tutti gli argomenti della riga di comando a destra del '\ C' in un singolo arg? –

+0

Funziona solo se non ho spazi negli argomenti passati allo script. – Barak

risposta

3

Diversi suggerimenti qui:

  • Fa l'ingresso con gli spazi devono essere trattati come singola stringa (con gli spazi), o id in effettivi diversi ingressi? Se la prima opzione è il caso vorrei suggerire di citare per il runtime di Windows:

ProcessBuilder pb = new ProcessBuilder("cmd.exe", "/c", 
"run.bat", "\"Some Input With Spaces\"", 
">>", "stdout.txt","2>>", "stderr.txt"); 
  • Invece di redirigere l'input per stdout.txt e stderr.txt usando la shell, perché non farlo usando Java usando getOutputStream() e getErrorStream()? Ecco un esempio che utilizza il pacchetto IO di Guava. Naturalmente si consiglia di avere quelle in thread separati, è necessario una corretta gestione delle eccezioni, ecc

InputStream stdout = new BufferedInputStream(proc.getInputStream()); 
FileOutputStream stdoutFile = new FileOutputStream("stdout.txt"); 
ByteStreams.copy(stdout, stdoutFile); 

InputStream stderr = new BufferedInputStream(proc.getErrorStream()); 
FileOutputStream stderrFile = new FileOutputStream("stderr.txt"); 
ByteStreams.copy(stderr, stderrFile); 

stdout.close(); 
stderr.close(); 
stdoutFile.close(); 
stderrFile.close(); 
  • Un'altra opzione, perché non creare un wrapper run.bat che renderà i reindirizzamenti?

@echo off 
cmd.exe /c run.bat "%1" >> "%2" 2>> "%3" 
+0

Il processo che viene eseguito potrebbe essere di lunga durata. Se leggo l'output del processo nel processo Java e muore, l'output del processo verrà memorizzato nel buffer e alla fine il processo esterno si arresterà. Il processo Java non dovrebbe interferire con quello esterno in alcun modo. Questo è il motivo per cui le piping al file dovrebbero essere fatte dal sistema operativo, in qualche modo. – Barak

+0

Per quanto riguarda gli spazi nell'input, è possibile qualsiasi opzione. La riga di comando è configurata utilizzando un elenco , che consente di passare qualsiasi combinazione. Con il JDK pre 6u45, l'implementazione ProcessBuilder ha funzionato in questo modo senza alcun problema. – Barak

+0

La creazione di uno script wrapper è un'opzione, ma lo script dovrebbe trovarsi nella stessa directory dello script esterno (nel caso in cui ci siano ulteriori riferimenti di file e directory nello script). Questo è 'sporco': voglio eseguire il codice nel modo meno invasivo possibile e aggiungere file generati può essere problematico. – Barak

0

Usa getOutputStream() sul processo, invece di utilizzare System.out.println(). A volte la semantica cambia tra le implementazioni Java.

Questo sembra essere un bugfix in realtà - l'implementazione più recente ha un senso.