Starten von wkhtmltopdf aus Runtime.getRuntime (). exec (): wird nie beendet?

8

Ich starte wkhtmltopdf aus meiner Java-App heraus (Teil eines Tomcat-Servers, der im Debug-Modus in Eclipse Helios unter Win7 64-bit läuft): Ich würde gerne darauf warten, dass es fertig ist, dann mache mehr Sachen.

%Vor%

Aber waitFor() kehrt nie zurück. Ich kann den Prozess immer noch im Windows Task-Manager sehen (mit der Befehlszeile, die ich an exec () übergeben habe: sieht gut aus). UND ES FUNKTIONIERT. wkhtmltopdf erzeugt das PDF, das ich erwarten würde, genau dort, wo ich es erwarten würde. Ich kann es öffnen, umbenennen, was auch immer, auch während der Prozess noch läuft (bevor ich es manuell beende).

Über die Befehlszeile ist alles in Ordnung:

%Vor%

Der Prozess geht gut und das Leben geht weiter.

Was also bewirkt runtime.exec() , dass wkhtmltopdf niemals beendet wird?

Ich könnte proc.getInputStream () aufrufen und nach "Done" suchen, aber das ist ... abscheulich. Ich möchte etwas, das allgemeiner ist.

Ich habe exec () mit und ohne Arbeitsverzeichnis aufgerufen. Ich habe es mit und ohne ein leeres "env" -Array versucht. Keine Freude.

Warum hängt mein Prozess, und was kann ich tun, um es zu beheben?

PS: Ich habe das mit ein paar anderen Befehlszeilen-Apps versucht, und beide zeigen das gleiche Verhalten.

Weitere Exec-Probleme.

Ich versuche Standard out & amp; Fehler, ohne Erfolg. Von der Befehlszeile weiß ich, dass es etwas Bemerkenswertes wie meine Befehlszeilenerfahrung geben sollte, aber wenn ich den von proc.getInputStream () zurückgegebenen Eingabestream lese, bekomme ich sofort ein EOL (-1, ich benutze inputStream.read() ).

Ich habe das JavaDoc für Process überprüft und das gefunden

  

Der übergeordnete Prozess verwendet diese Datenströme, um Eingaben in den Unterprozess zu leiten und Ausgaben daraus zu erhalten. Da einige native Plattformen nur eine begrenzte Puffergröße für Standardeingabe- und -ausgabeströme bereitstellen, kann das fehlerhafte Schreiben des Eingabedatenstroms oder das Lesen des Ausgabestreams des Unterprozesses dazu führen, dass [b] der Unterprozess blockiert und sogar blockiert. [/ B]

Hervorhebung hinzugefügt. Also habe ich das versucht. Die erste 'read ()' auf dem Standard Out inputStream blockiert bis ich den Prozess beendet habe ...

MIT WKHTMLTOPDF

Mit der generischen Kommandozeile ap & amp; keine params also sollte es "dump usage und terminieren", es saugt die entsprechende std :: out, dann endet.

Interessant!

JVM Versionsproblem? Ich benutze 1.6.0_23. Das Neueste ist ... v24. Ich habe gerade das Änderungsprotokoll überprüft und sehe nichts vielversprechendes, aber ich werde versuchen, es trotzdem zu aktualisieren.

Okay. Lassen Sie die Eingabestreams nicht ausfüllen oder sie blockieren. Prüfen. .close() kann dies ebenfalls verhindern, ist aber nicht besonders hell.

Das funktioniert im Allgemeinen (einschließlich der generischen Kommandozeilen-Apps, die ich getestet habe).

Im Speziellen fällt es jedoch ab. Es scheint, dass wkhtmltopdf einige Terminalmanipulation / cursor Zeug verwendet, um eine ASCII-Grafik Fortschrittsbalken zu machen. Ich glaube, dass dies bewirkt, dass der inputStream sofort EOF zurückgibt, anstatt mir die richtigen Werte zu geben.

Irgendwelche Ideen? Kaum ein Deal-Breaker, aber es wäre definitiv Nice To Have.

    
Mark Storer 31.03.2011, 20:59
quelle

4 Antworten

4

Ein Prozess hat 3 Ströme: Eingabe, Ausgabe und Fehler. Sie können Ausgabe- und Fehlerstream gleichzeitig mit separaten Prozessen lesen. siehe diese Frage und ihre Annahme antworten Sie und auch dieses zum Beispiel.

    
MByD 31.03.2011, 21:10
quelle
10

Ich hatte genau das gleiche Problem wie Sie und ich haben es gelöst. Hier sind meine Ergebnisse:

Aus irgendeinem Grund geht die Ausgabe von wkhtmltopdf an STDERR des Prozesses und NOT STDOUT. Ich habe dies verifiziert, indem ich sowohl wkhtmltopdf von Java als auch perl

aufgerufen habe

Also, zum Beispiel in Java, müssten Sie tun:

%Vor%

Wenn Sie einen Prozess aus Java erzeugen, MÜSSEN Sie aus den stdout- und stderr-Streams lesen (auch wenn Sie nichts damit machen), da sonst der Stream-Puffer gefüllt wird und der Prozess hängen bleibt und niemals zurückkehrt.

Um Ihren Code zukunftssicher zu machen, nur für den Fall, dass die Entwickler von wkhtmltopdf beschließen, in stdout zu schreiben, können Sie stderr des untergeordneten Prozesses auf stdout umleiten und nur einen solchen Stream lesen:

%Vor%

Eigentlich mache ich das in all den Fällen, in denen ich einen externen Prozess von Java erzeugen muss. So muss ich nicht zwei Streams lesen.

Sie sollten auch die Streams des erzeugten Prozesses in verschiedenen Threads lesen, wenn Sie nicht möchten, dass Ihr Haupt-Thread blockiert, da das Lesen von Streams blockiert.

Hoffe, das hilft.

UPDATE : Ich habe dieses Problem im Bereich angesprochen Projektseite und wurde geantwortet, dass dies von Entwurf ist, weil wkhtmltopdf unterstützt, die tatsächliche pdf-Ausgabe in STDOUT zu geben. Bitte beachten Sie den Link für weitere Details und Java-Code.

    
Riyas Valiya 16.01.2012 19:08
quelle
2
%Vor%     
yogeshP 02.11.2012 12:13
quelle