문제

프로세스를 실행하고 입력, 출력 및 오류 스트림으로 작업을 수행하려고합니다. 이것을하는 명백한 방법은 select(),하지만 내가 자바에서 찾을 수있는 유일한 것은 Selector.select(), 그것은 a Channel. a를 얻는 것은 불가능한 것 같습니다 Channel an InputStream 또는 OutputStream (FileStream a getChannel() 방법이지만 여기서는 도움이되지 않습니다)

대신, 나는 모든 스트림을 투표하기 위해 몇 가지 코드를 썼습니다.

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

결코 종료되지 않는다는 점을 제외하고는 작동합니다. 스트림 중 하나가 파일 끝에 도달하면 available() 0을 반환합니다 read() 호출되지 않으며 EOF를 나타내는 -1 리턴을 얻지 못합니다.

하나의 솔루션은 EOF를 감지하는 비 블로킹 방법입니다. 문서에서 어디서나 볼 수 없습니다. 또는 내가하고 싶은 일을하는 더 좋은 방법이 있습니까?

나는 여기 에이 질문을 본다 :링크 텍스트그리고 그것이 내가 원하는 것을 정확하게 수행하지는 않지만, 나는 아마도 내가 가진 특정 문제에 대해 각 스트림에 대해 별도의 스레드를 산란하는 것으로 아마도 그 아이디어를 사용할 수 있습니다. 그러나 확실히 그렇게 할 수있는 유일한 방법은 없습니까? 분명히 각각의 스레드를 사용하지 않고 여러 스트림에서 읽을 수있는 방법이 있어야합니까?

도움이 되었습니까?

해결책

당신이 말했듯이, 해결책 이 답변에 설명되어 있습니다 프로세스에서 stdout과 stderr를 모두 읽는 전통적인 방법입니다. 스레드마다 스레드는 약간 성가시더라도 갈 길입니다.

다른 팁

실제로 모니터링하려는 각 스트림마다 스레드를 산란하는 경로를 가야합니다. 유스 케이스가 문제의 프로세스의 stdout과 stderr를 결합 할 수있는 경우 하나의 스레드 만 필요합니다. 그렇지 않으면 두 스레드가 필요합니다.

외부 프로세스를 시작하고 출력을 취하고 동시에 오류 및 프로세스 종료를 찾고 종료 할 수있는 동안 작업을 수행 해야하는 프로젝트 중 하나에서 제대로 얻는 데 시간이 걸렸습니다. Java 앱의 사용자가 작업을 취소 할 때.

런 () 메소드가 다음과 같은 모습을 보이는 시청 부분을 캡슐화하기 위해 다소 간단한 클래스를 만들었습니다.

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

호출쪽에는 다음과 같습니다.

    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;

불행히도 나는 독립적 인 실행 가능한 예를들을 필요는 없지만 아마도 이것이 도움이 될 것입니다. 다시해야한다면 스스로 제작 한 스톱 플래그 대신 thread.interrupt () 메소드를 사용하는 것을 다시 살펴볼 것입니다 (휘발성을 선언 할 마음이 있습니다!). :)

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top