Frage

Ich versuche, ein Prozess und tun Dinge mit seiner Eingabe, Ausgabe und Fehlerströme zu laufen. Der offensichtliche Weg, dies zu tun, ist so etwas wie select() zu verwenden, aber das einzige, was ich in Java finden, die das tut ist Selector.select(), die ein Channel nimmt. Es scheint nicht möglich zu sein, eine Channel von einem InputStream oder OutputStream zu erhalten (FileStream eine getChannel() Methode hat aber das hilft nicht hier)

Also, anstatt schrieb ich einige Code alle Streams abzufragen:

while( !out_eof || !err_eof )
{
    while( out_str.available() )
    {
        if( (bytes = out_str.read(buf)) != -1 )
        {
            // Do something with output stream
        }
        else
            out_eof = true;
    }
    while( err_str.available() )
    {
        if( (bytes = err_str.read(buf)) != -1 )
        {
            // Do something with error stream
        }
        else
            err_eof = true;
    }
    sleep(100);
}

, die funktionieren, mit der Ausnahme, dass es endet nie. Wenn einer der Ströme Ende der Datei erreicht, available() gibt Null zurück, so wird read() nicht genannt und wir bekommen nie die -1 Rückkehr, die EOF angeben würde.

Eine Lösung wäre eine nicht-blockierende Art und Weise EOF zu erkennen. Ich kann nicht überall eine in der Dokumentation sehen. Alternativ gibt es eine bessere Art und Weise zu tun, was ich tun will?

Ich sehe diese Frage hier:

War es hilfreich?

Lösung

Wie Sie sagten, die Lösung in dieser skizzierte Antwort ist die traditionelle Art und Weise Fehler- und Standardausgaben von einem Prozess des Lesens. Ein Thread-pro-Strom ist der Weg zu gehen, auch wenn es etwas ärgerlich ist.

Andere Tipps

Sie werden in der Tat die Strecke zu gehen, um einen Thread für jeden Strom von Laichen Sie überwachen möchten. Wenn Ihr stdout und stderr Anwendungsfall erlaubt sowohl des Prozesses in Frage zum Kombinieren benötigen Sie nur einen Thread, sonst zwei benötigt werden.

Es dauerte einige Zeit, es richtig in einem unserer Projekte zu bekommen, wo ich einen externen Prozess zu starten, nehmen seinen Ausgang und mit ihm etwas zu tun, während zugleich für Fehler und Prozessbeendigung suchen und auch in der Lage sein um ihn zu kündigen, wenn der Benutzer die Java-Anwendung wird der Vorgang abgebrochen.

habe ich eine ziemlich einfache Klasse, die gerade Teil deren Methode run () sieht wie folgt aus etwas zu kapseln:

public void run() {
    BufferedReader tStreamReader = null;
    try {
        while (externalCommand == null && !shouldHalt) {
            logger.warning("ExtProcMonitor("
                           + (watchStdErr ? "err" : "out")
                           + ") Sleeping until external command is found");
            Thread.sleep(500);
        }
        if (externalCommand == null) {
            return;
        }
        tStreamReader =
                new BufferedReader(new InputStreamReader(watchStdErr ? externalCommand.getErrorStream()
                        : externalCommand.getInputStream()));
        String tLine;
        while ((tLine = tStreamReader.readLine()) != null) {
            logger.severe(tLine);
            if (filter != null) {
                if (filter.matches(tLine)) {
                    informFilterListeners(tLine);
                    return;
                }
            }
        }
    } catch (IOException e) {
        logger.logExceptionMessage(e, "IOException stderr");
    } catch (InterruptedException e) {
        logger.logExceptionMessage(e, "InterruptedException waiting for external process");
    } finally {
        if (tStreamReader != null) {
            try {
                tStreamReader.close();
            } catch (IOException e) {
                // ignore
            }
        }
    }
}

Auf der rufenden Seite sieht es wie folgt aus:

    Thread tExtMonitorThread = new Thread(new Runnable() {

        public void run() {
            try {
                while (externalCommand == null) {
                    getLogger().warning("Monitor: Sleeping until external command is found");
                    Thread.sleep(500);
                    if (isStopRequested()) {
                        getLogger()
                                .warning("Terminating external process on user request");
                        if (externalCommand != null) {
                            externalCommand.destroy();
                        }
                        return;
                    }
                }
                int tReturnCode = externalCommand.waitFor();
                getLogger().warning("External command exited with code " + tReturnCode);
            } catch (InterruptedException e) {
                getLogger().logExceptionMessage(e, "Interrupted while waiting for external command to exit");
            }
        }
    }, "ExtCommandWaiter");

    ExternalProcessOutputHandlerThread tExtErrThread =
            new ExternalProcessOutputHandlerThread("ExtCommandStdErr", getLogger(), true);
    ExternalProcessOutputHandlerThread tExtOutThread =
            new ExternalProcessOutputHandlerThread("ExtCommandStdOut", getLogger(), true);
    tExtMonitorThread.start();
    tExtOutThread.start();
    tExtErrThread.start();
    tExtErrThread.setFilter(new FilterFunctor() {

        public boolean matches(Object o) {
            String tLine = (String)o;
            return tLine.indexOf("Error") > -1;
        }
    });

    FilterListener tListener = new FilterListener() {
        private boolean abortFlag = false;

        public boolean shouldAbort() {
            return abortFlag;
        }

        public void matched(String aLine) {
            abortFlag = abortFlag || (aLine.indexOf("Error") > -1);
        }

    };

    tExtErrThread.addFilterListener(tListener);
    externalCommand = new ProcessBuilder(aCommand).start();
    tExtErrThread.setProcess(externalCommand);
    try {
        tExtMonitorThread.join();
        tExtErrThread.join();
        tExtOutThread.join();
    } catch (InterruptedException e) {
        // when this happens try to bring the external process down 
        getLogger().severe("Aborted because auf InterruptedException.");
        getLogger().severe("Killing external command...");
        externalCommand.destroy();
        getLogger().severe("External command killed.");
        externalCommand = null;
        return -42;
    }
    int tRetVal = tListener.shouldAbort() ? -44 : externalCommand.exitValue();

    externalCommand = null;
    try {
        getLogger().warning("command exit code: " + tRetVal);
    } catch (IllegalThreadStateException ex) {
        getLogger().warning("command exit code: unknown");
    }
    return tRetVal;

Leider habe ich nicht für ein in sich geschlossenes runnable Beispiel, aber vielleicht hilft. Wenn ich es zu tun hatte, wieder würde ich einen anderen Blick haben die Thread.interrupt () -Methode anstelle einer selbstgemachten Stop-Flag bei Verwendung von (mind es flüchtig zu erklären!), Aber ich lasse, dass für eine andere Zeit. :)

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top