2013-06-13 2 views
7

Ich habe die folgende Windows-Batch-Datei (run.bat):Wie kann ich Rohr Prozess Ausgabe in eine Datei unter Windows und JDK 6u45

@echo off 
echo hello batch file to sysout 

und den folgenden Java-Code, der die Batch-Dateien und Umleitungen läuft Ausgabe in eine Datei:

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

auf JDKs bis einschließlich JDK6u43 ich folgende Ausgabe:

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

und Die Skriptausgabe wird in die Datei geschrieben. Ab JDK 6u45 und 7, erhalte ich die folgende Ausgabe:

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 

Und nichts in die Ausgabedatei geschrieben wird. http://www.oracle.com/technetwork/java/javase/6u45-relnotes-1932876.html

Was ist der richtige Weg unter Windows einen Prozess, beginnend mit Ausgabe auf Dateien umgeleitet wird:

Dies sein kann oder nicht auf die in Runtime.exec(), beschrieben bei Änderungen im Zusammenhang?

Hinweis: In einem realen Szenario, das Kommando auszuführen kann Parameter mit Leerzeichen enthält, wie in:

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

Hilft es, alle Befehlszeile args rechts von '\ c 'in eine kombinieren einzelne arg? –

+0

Dies funktioniert nur, wenn ich keine Leerzeichen in den Argumenten habe, die an das Skript übergeben werden. – Barak

Antwort

3

Mehrere Vorschläge hier:

  • Ist die Eingabe mit den Räumen müssen als einzelne String behandelt werden (mit Leerzeichen) oder id es in der tatsächlichen mehrere Eingänge? Wenn die erste Option der Fall ist, würde ich vorschlagen, es für den Windows-Runtime zu zitieren:

ProcessBuilder pb = new ProcessBuilder("cmd.exe", "/c", 
"run.bat", "\"Some Input With Spaces\"", 
">>", "stdout.txt","2>>", "stderr.txt"); 
  • Statt Umleiten die Eingabe in stdout.txt und stderr.txt mit der Schale, Warum nicht Java mit getOutputStream() und getErrorStream() verwenden? Hier ist ein Beispiel mit Guava's IO-Paket. Natürlich können Sie die in separaten Threads haben wollen, können Sie die richtige Ausnahmebehandlung benötigen, usw.

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(); 
  • Eine weitere Option, warum nicht einen run.bat Wrapper erstellen, die die Umleitungen machen?

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

Der Prozess, der ausgeführt wird, kann lange ausgeführt werden. Wenn ich die Prozessausgabe im Java-Prozess lese und sie stirbt, wird die Prozessausgabe gepuffert und der externe Prozess wird schließlich angehalten. Der Java-Prozess sollte den externen Prozess in keiner Weise stören. Aus diesem Grund sollte die Übertragung der Datei vom Betriebssystem irgendwie durchgeführt werden. – Barak

+0

In Bezug auf Leerzeichen in der Eingabe sind alle Optionen möglich. Die Befehlszeile wird mithilfe einer Liste konfiguriert, so dass eine beliebige Kombination übergeben werden kann. Mit dem pre 6u45 JDK funktionierte die ProcessBuilder-Implementierung problemlos. – Barak

+0

Das Erstellen eines Wrapper-Skripts ist eine Option, aber das Skript muss sich im selben Verzeichnis wie das externe Skript befinden (falls im Skript weitere Verweise auf Dateien und Verzeichnisse vorhanden sind). Dies ist "schmutzig" - ich möchte den Code so unauffällig wie möglich ausführen, und das Hinzufügen von generierten Dateien kann problematisch sein. – Barak

0

Verwenden getOutputStream() auf dem Prozess, statt System.out.println() zu verwenden. Manchmal ändert sich die Semantik zwischen Java-Implementierungen.

Dies scheint eigentlich ein Bugfix zu sein - die neuere Implementierung macht Sinn.

Verwandte Themen