2017-05-05 4 views
2

Ich bin auf ein seltsames Problem gestoßen. Ich habe Process Builder mehrmals verwendet, um eine ausführbare Datei von einem Programm aufzurufen, bin aber noch nie zuvor darauf gestoßen. Für Debug-Zwecke habe ich eine Methode erstellt, die die Ausgabe der ausführbaren Datei nach System.out druckt. Alles hat gut funktioniert und mein Programm hat alle Test-Gifs, die ich lief, schön exportiert.Der Prozess wird nicht ausgeführt, es sei denn Druckausgabe + Processbuilder

Als es an der Zeit war, dieses Programm richtig für 1000+ Gifs zu starten, habe ich die Ausdruckmethode auskommentiert, um die Leistung zu verbessern. Sobald das ganze Programm abgelaufen war, kam ich zurück und stellte fest, dass das exportGif nicht funktionierte. Das Programm lief ohne Fehler, aber der Aufruf des Prozesses führte die Gifs nicht wie erwartet aus.

Nach dem Isolieren von Zeilen in der Ausdruckmethode scheint es, dass das entscheidende Bit des Codes die reader.readLine() ist. Warum sollte das der Fall sein? Die ausführbare Datei sollte bereits ausgeführt worden sein, die Debug-Methode sollte nur den Ausgabestrom nach der Tat lesen, richtig? Ich würde lieber nicht jedes Mal den Ausgabestrom durchlaufen, da das Programm dadurch erheblich langsamer wird.

private void printProcessOutput(Process process){ 
     BufferedReader reader = 
       new BufferedReader(new InputStreamReader(process.getInputStream())); 
     StringBuilder builder = new StringBuilder(); 
     String line = null; 

     try{ 
      while ((line = reader.readLine()) != null) { 
       builder.append(line); 
       builder.append(System.getProperty("line.separator")); 
      } 
     }catch(IOException e){ 
      e.printStackTrace(); 
     } 

     System.out.println(builder.toString()); 
    } 

    private void exportGIF(String dirPath) throws IOException { 
     List<String> lines = Arrays.asList("/Users/IdeaProjects/MasterFormat/MasterFormat-Java/MasterFormat/timMaster_4.1.png \"{200.0,467.0}\""); 
     Path headImageFile = Paths.get(System.getProperty("user.dir") + File.separator + "headImageInfo.txt"); 
     Files.write(headImageFile, lines, Charset.forName("UTF-8")); 

     String templatePath = dirPath + File.separator + "template.mp4"; 
     String outputPath = dirPath + File.separator; 
     String headImagePath = headImageFile.toString(); 
     String gifExportExecPath = "/Users/IdeaProjects/MasterFormat/MasterFormat-Java/MasterFormat/GIFExport"; 

     Process process = new ProcessBuilder(gifExportExecPath, "-s", templatePath, "-o", outputPath, "-h", headImagePath).start(); 

     printProcessOutput(process); 

     Files.delete(headImageFile); 
    } 

EDIT

Eine Sache, die ich hinzufügen sollte. Ich habe bemerkt, dass wenn ich die Debug-Methode auskommentiere, sie alle 1000+ Iterationen in weniger als zehn Minuten durchläuft. Aber natürlich werden die Gifs nicht exportiert (die ausführbare Datei läuft nicht ...? Nicht sicher).

Wenn ich die Ausdruckmethode einschließen, ist es viel langsamer. Ich habe versucht, es über Nacht laufen, aber es blieb nach 183 Iterationen stecken. Ich habe versucht, ein Profiling zu machen, um zu sehen, ob es zu etwas Thrashing führte, aber der GC scheint gut zu laufen.

+1

Sie schreiben „Das Programm lief ohne Fehler“, dass Mittel es hat nicht "hängen" richtig? Es ist also nicht dasselbe wie hier angenommen: http://stackoverflow.com/questions/22953760/processbuilder-process-not-running?rq=1 – dbalakirev

Antwort

2

Sie müssen die Ausgabe des Prozesses verbrauchen oder es hängt möglicherweise. Sie können also printProcessOutput(process); nicht auskommentieren. Stattdessen kommentieren die Zeilen aus, die das Drucken tatsächlich tun:

try{ 
    while ((line = reader.readLine()) != null) { 
    //builder.append(line); 
    //builder.append(System.getProperty("line.separator")); 
    } 
} catch(IOException e){ 
    e.printStackTrace(); 
} 
//System.out.println(builder.toString()); 

ich in der Regel diese Methode verwenden, die auch den Fehlerstrom umleitet:

public static void runProcess(ProcessBuilder pb) throws IOException { 
    pb.redirectErrorStream(true); 
    Process p = pb.start(); 
    BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())); 
    String line; 
    while ((line = reader.readLine()) != null) { 
    //System.out.println(line); 
    } 
} 
+0

Aus dem Javadoc for Process: "Standardmäßig hat der erstellte Subprozess keine ein eigenes Terminal oder eine Konsole: Alle Standard-E/A-Operationen (dh stdin, stdout, stderr) werden zum übergeordneten Prozess umgeleitet, [...] da einige native Plattformen nur eine begrenzte Puffergröße für Standard-Eingabe- und -Ausgabestreams bieten. Wenn der Eingabestream nicht sofort geschrieben wird oder der Ausgabestream des Subprozesses nicht gelesen wird, kann der Subprozess blockiert oder sogar blockiert werden. " Also ja, der Prozess wartet tatsächlich auf die Fertigstellung, und Sie können Speicherlecks erhalten, die die Fehler/Aus-Ströme nicht verbrauchen. –

Verwandte Themen