Process process = Runtime.getRuntime().exec("tasklist");
BufferedReader reader =
new BufferedReader(new InputStreamReader(process.getInputStream()));
process.waitFor();
Process process = Runtime.getRuntime().exec("tasklist");
BufferedReader reader =
new BufferedReader(new InputStreamReader(process.getInputStream()));
process.waitFor();
답변:
waitFor()
돌아 오지 않는 데는 여러 가지 이유가 있습니다.
그러나 일반적으로 실행 된 명령이 종료되지 않는다는 사실로 귀결됩니다.
이것 역시 여러 가지 이유가있을 수 있습니다.
한 가지 일반적인 이유는 프로세스가 일부 출력을 생성하고 적절한 스트림에서 읽지 않기 때문입니다. 즉, 버퍼가 가득 차면 프로세스가 차단되고 프로세스가 계속 읽기를 기다립니다. 당신의 프로세스는 다른 프로세스가 끝날 때까지 기다립니다 (당신의 프로세스를 기다리기 때문이 아닙니다 ...). 이것은 고전적인 교착 상태 상황입니다.
차단되지 않도록 프로세스 입력 스트림에서 지속적으로 읽어야합니다.
"When Runtime.exec () wo n't"Runtime.exec()
라는 모든 함정을 설명하고 그에 대한 방법을 보여주는 멋진 기사 가 있습니다.
waitFor()
반환되지 않는지 알아 보려면 유용한 코드에 대한 Peter Lawrey 답변을 살펴보십시오 .
완료되기를 기다리기 전에 출력을 읽지 않는 것 같습니다. 출력이 버퍼를 채우지 않는 경우에만 괜찮습니다. 그렇다면 출력 catch-22를 읽을 때까지 기다립니다.
읽지 않은 오류가있을 수 있습니다. 이 경우 응용 프로그램이 중지되고 waitFor가 영원히 대기합니다. 이 문제를 해결하는 간단한 방법은 오류를 일반 출력으로 리디렉션하는 것입니다.
ProcessBuilder pb = new ProcessBuilder("tasklist");
pb.redirectErrorStream(true);
Process process = pb.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null)
System.out.println("tasklist: " + line);
process.waitFor();
pb.redirectError(new File("/dev/null"));
redirectError
자바 1.7 이후에서만 사용할 수 있습니다
또한 Java 문서에서 :
java.lang
수업 과정
일부 네이티브 플랫폼은 표준 입력 및 출력 스트림에 제한된 버퍼 크기 만 제공하기 때문에 입력 스트림을 즉시 쓰거나 하위 프로세스의 출력 스트림을 읽지 못하면 하위 프로세스가 차단되고 교착 상태가 될 수도 있습니다.
Process에서 입력 스트림의 버퍼 (하위 프로세스의 출력 스트림으로 파이프)를 지우지 못하면 하위 프로세스가 차단 될 수 있습니다.
이 시도:
Process process = Runtime.getRuntime().exec("tasklist");
BufferedReader reader =
new BufferedReader(new InputStreamReader(process.getInputStream()));
while ((reader.readLine()) != null) {}
process.waitFor();
DefaultExecutor executor = new DefaultExecutor(); PumpStreamHandler pumpStreamHandler = new PumpStreamHandler(stdoutOS, stderrOS); executor.setStreamHandler(pumpStreamHandler); executor.execute(cmdLine);
여기서 stoutOS 및 stderrOS는 BufferedOutputStream
적절한 파일에 작성하기 위해 만든 것입니다.
process.close()
. 그러나 위에서 제안한대로 입력 스트림을 열고 즉시 닫으면 문제가 사라집니다. 그래서 제 경우에는 Spring이 스트림 닫기 신호를 기다리고있었습니다. Java 8 auto closable을 사용하고 있지만.
이전 답변에 추가하고 싶지만 댓글을 달 담당자가 없기 때문에 답변 만 추가하겠습니다. 이것은 Java로 프로그래밍하는 Android 사용자를 대상으로합니다.
RollingBoy의 게시물에 따르면이 코드는 거의 저에게 효과적이었습니다.
Process process = Runtime.getRuntime().exec("tasklist");
BufferedReader reader =
new BufferedReader(new InputStreamReader(process.getInputStream()));
while ((reader.readLine()) != null) {}
process.waitFor();
제 경우에는 return ( "ip adddr flush eth0")없이 명령문을 실행했기 때문에 waitFor ()가 해제되지 않았습니다. 이 문제를 해결하는 쉬운 방법은 단순히 진술에 항상 무언가를 반환하도록하는 것입니다. 저에게 이것은 "ip adddr flush eth0 && echo done"실행을 의미했습니다. 하루 종일 버퍼를 읽을 수 있지만 아무것도 반환되지 않으면 스레드가 대기를 해제하지 않습니다.
누군가에게 도움이되기를 바랍니다!
process.waitFor()
매달리는 것이 매달려 있다고 생각하지 않습니다 reader.readLine()
. 나는 waitFor(long,TimeUnit)
무언가가 잘못되면 to timeout 을 사용하려고 시도했고 그것이 중단 된 읽기임을 발견했습니다. 어느 timeouted 버전은 읽기를 수행하는 다른 스레드를 필요로한다 ...
다른 사람들이 언급했듯이 stderr 및 stdout 을 사용해야합니다 .
다른 답변과 비교할 때 Java 1.7 이후로 훨씬 쉽습니다. stderr 및 stdout 을 읽기 위해 더 이상 스레드를 직접 만들 필요가 없습니다 .
그냥를 사용 ProcessBuilder
하고 방법을 사용 redirectOutput
중 하나와 함께 redirectError
또는 redirectErrorStream
.
String directory = "/working/dir";
File out = new File(...); // File to write stdout to
File err = new File(...); // File to write stderr to
ProcessBuilder builder = new ProcessBuilder();
builder.directory(new File(directory));
builder.command(command);
builder.redirectOutput(out); // Redirect stdout to file
if(out == err) {
builder.redirectErrorStream(true); // Combine stderr into stdout
} else {
builder.redirectError(err); // Redirect stderr to file
}
Process process = builder.start();
출력과 오류를 동시에 소비해야합니다.
private void runCMD(String CMD) throws IOException, InterruptedException {
System.out.println("Standard output: " + CMD);
Process process = Runtime.getRuntime().exec(CMD);
// Get input streams
BufferedReader stdInput = new BufferedReader(new InputStreamReader(process.getInputStream()));
BufferedReader stdError = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String line = "";
String newLineCharacter = System.getProperty("line.separator");
boolean isOutReady = false;
boolean isErrorReady = false;
boolean isProcessAlive = false;
boolean isErrorOut = true;
boolean isErrorError = true;
System.out.println("Read command ");
while (process.isAlive()) {
//Read the stdOut
do {
isOutReady = stdInput.ready();
//System.out.println("OUT READY " + isOutReady);
isErrorOut = true;
isErrorError = true;
if (isOutReady) {
line = stdInput.readLine();
isErrorOut = false;
System.out.println("=====================================================================================" + line + newLineCharacter);
}
isErrorReady = stdError.ready();
//System.out.println("ERROR READY " + isErrorReady);
if (isErrorReady) {
line = stdError.readLine();
isErrorError = false;
System.out.println("ERROR::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::" + line + newLineCharacter);
}
isProcessAlive = process.isAlive();
//System.out.println("Process Alive " + isProcessAlive);
if (!isProcessAlive) {
System.out.println(":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: Process DIE " + line + newLineCharacter);
line = null;
isErrorError = false;
process.waitFor(1000, TimeUnit.MILLISECONDS);
}
} while (line != null);
//Nothing else to read, lets pause for a bit before trying again
System.out.println("PROCESS WAIT FOR");
process.waitFor(100, TimeUnit.MILLISECONDS);
}
System.out.println("Command finished");
}
비슷한 문제를 목격했다고 생각합니다. 일부 프로세스가 시작되었고 성공적으로 실행되는 것처럼 보였지만 완료되지 않았습니다. waitFor () 함수는 작업 관리자에서 프로세스를 종료 한 경우를 제외하고는 영원히 기다리고있었습니다.
그러나 명령 줄 길이가 127 자 이하인 경우 모든 것이 잘 작동했습니다. 긴 파일 이름이 불가피한 경우 환경 변수를 사용하여 명령 줄 문자열을 짧게 유지할 수 있습니다. 실제로 실행하려는 프로그램을 호출하기 전에 환경 변수를 설정하는 배치 파일 (FileWriter 사용)을 생성 할 수 있습니다. 이러한 배치의 내용은 다음과 같습니다.
set INPUTFILE="C:\Directory 0\Subdirectory 1\AnyFileName"
set OUTPUTFILE="C:\Directory 2\Subdirectory 3\AnotherFileName"
set MYPROG="C:\Directory 4\Subdirectory 5\ExecutableFileName.exe"
%MYPROG% %INPUTFILE% %OUTPUTFILE%
마지막 단계는 런타임을 사용하여이 배치 파일을 실행하는 것입니다.
여기 저에게 맞는 방법이 있습니다. 참고 :이 메서드에는 적용되지 않는 코드가 있으므로 무시하십시오. 예 : "logStandardOut (...), git-bash, etc".
private String exeShellCommand(String doCommand, String inDir, boolean ignoreErrors) {
logStandardOut("> %s", doCommand);
ProcessBuilder builder = new ProcessBuilder();
StringBuilder stdOut = new StringBuilder();
StringBuilder stdErr = new StringBuilder();
boolean isWindows = System.getProperty("os.name").toLowerCase().startsWith("windows");
if (isWindows) {
String gitBashPathForWindows = "C:\\Program Files\\Git\\bin\\bash";
builder.command(gitBashPathForWindows, "-c", doCommand);
} else {
builder.command("bash", "-c", doCommand);
}
//Do we need to change dirs?
if (inDir != null) {
builder.directory(new File(inDir));
}
//Execute it
Process process = null;
BufferedReader brStdOut;
BufferedReader brStdErr;
try {
//Start the command line process
process = builder.start();
//This hangs on a large file
// /programming/5483830/process-waitfor-never-returns
//exitCode = process.waitFor();
//This will have both StdIn and StdErr
brStdOut = new BufferedReader(new InputStreamReader(process.getInputStream()));
brStdErr = new BufferedReader(new InputStreamReader(process.getErrorStream()));
//Get the process output
String line = null;
String newLineCharacter = System.getProperty("line.separator");
while (process.isAlive()) {
//Read the stdOut
while ((line = brStdOut.readLine()) != null) {
stdOut.append(line + newLineCharacter);
}
//Read the stdErr
while ((line = brStdErr.readLine()) != null) {
stdErr.append(line + newLineCharacter);
}
//Nothing else to read, lets pause for a bit before trying again
process.waitFor(100, TimeUnit.MILLISECONDS);
}
//Read anything left, after the process exited
while ((line = brStdOut.readLine()) != null) {
stdOut.append(line + newLineCharacter);
}
//Read anything left, after the process exited
while ((line = brStdErr.readLine()) != null) {
stdErr.append(line + newLineCharacter);
}
//cleanup
if (brStdOut != null) {
brStdOut.close();
}
if (brStdErr != null) {
brStdOut.close();
}
//Log non-zero exit values
if (!ignoreErrors && process.exitValue() != 0) {
String exMsg = String.format("%s%nprocess.exitValue=%s", stdErr, process.exitValue());
throw new ExecuteCommandException(exMsg);
}
} catch (ExecuteCommandException e) {
throw e;
} catch (Exception e) {
throw new ExecuteCommandException(stdErr.toString(), e);
} finally {
//Log the results
logStandardOut(stdOut.toString());
logStandardError(stdErr.toString());
}
return stdOut.toString();
}
시간 초과와 함께 대기를 피하는 것과 결합 된 스트림의 비동기 읽기는 문제를 해결합니다.
여기에서이를 설명하는 페이지를 찾을 수 있습니다. http://simplebasics.net/.net/process-waitforexit-with-a-timeout-will-not-be-able-to-collect-the-output-message/