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();
Yanıtlar:
waitFor()
Geri dönmeyen birçok neden var .
Ancak genellikle yürütülen komutun çıkmaması gerçeğine dayanır.
Bunun da birçok nedeni olabilir.
Yaygın bir neden, işlemin bir miktar çıktı üretmesi ve uygun akışlardan okumamanızdır. Bu, arabellek dolduğu anda işlemin engelleneceği ve işleminizin okumaya devam etmesini beklediği anlamına gelir. İşleminiz sırayla diğer işlemin bitmesini bekler (ki bu işleminizi beklediği için bitmez ...). Bu klasik bir kilitlenme durumudur.
Engellemediğinden emin olmak için işlem giriş akışını sürekli olarak okumanız gerekir.
Tüm tuzaklarını açıklayan güzel bir makale var Runtime.exec()
etraflarında ve gösterileri yolları denilen "Ne zaman Runtime.exec () olmaz" (evet, makale 2000 olmakla birlikte, içerik yine geçerlidir!)
waitFor()
geri dönmediğini öğrenmek için yararlı kod için Peter Lawrey yanıtına bir göz atın .
Görünüşe göre, bitmesini beklemeden çıktıyı okumuyorsunuz. Bu sadece çıktı arabelleği doldurmuyorsa iyidir. Eğer öyleyse, çıktıyı, catch-22'yi okuyana kadar bekler.
Belki de okumadığınız bazı hatalarınız vardır. Bu, uygulamanın durması ve sonsuza kadar beklemesi anlamına gelir. Bunu aşmanın basit bir yolu, hataları normal çıktıya yeniden yönlendirmektir.
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
yalnızca Java 1.7'den beri mevcuttur
Ayrıca Java belgesinden:
java.lang
Sınıf Süreci
Bazı yerel platformlar, standart giriş ve çıkış akışları için yalnızca sınırlı arabellek boyutu sağladığından, alt işlemin giriş akışının hemen yazılmaması veya çıkış akışının okunmaması, alt işlemin engellenmesine ve hatta kilitlenmesine neden olabilir.
Giriş akışı tamponunun (alt işlemin çıkış akışına giden) İşlemden temizlenememesi, bir alt işlemin bloke olmasına neden olabilir.
Bunu dene:
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);
Stdout ve stderr akışlarını aynı anda tüketmek için Apache Commons Exec işlevini kullanabilirsiniz: burada stoutOS ve stderrOS, BufferedOutputStream
uygun dosyalara yazmak için oluşturduğum s.
process.close()
. Ancak yukarıda önerildiği gibi giriş akışını açıp hemen kapattığımda sorun ortadan kalkıyor. Benim durumumda Bahar, akışın kapanma sinyalini bekliyordu. Java 8 otomatik kapatılabilir kullanmama rağmen.
Önceki cevaplara bir şeyler eklemek istiyorum ancak yorum yapacak temsilcim olmadığı için sadece bir cevap ekleyeceğim. Bu, Java'da programlama yapan android kullanıcılarına yöneliktir.
RollingBoy'daki gönderiye göre, bu kod neredeyse benim için çalıştı:
Process process = Runtime.getRuntime().exec("tasklist");
BufferedReader reader =
new BufferedReader(new InputStreamReader(process.getInputStream()));
while ((reader.readLine()) != null) {}
process.waitFor();
Benim durumumda, waitFor () yayınlanmıyordu çünkü dönüşü olmayan bir ifade ("ip adddr flush eth0") yürütüyordum. Bunu düzeltmenin kolay bir yolu, ifadenizde her zaman bir şey döndürmenizi sağlamaktır. Benim için bunun anlamı şuydu: "ip adddr flush eth0 && echo done". Tüm gün tamponu okuyabilirsiniz, ancak geri dönen hiçbir şey yoksa, iş parçacığınız asla beklemesini bırakmaz.
Umarım bu birine yardımcı olur!
process.waitFor()
öyle takılırsa o reader.readLine()
hiçbir çıkış varsa o takılıyor. Bir waitFor(long,TimeUnit)
şeyler ters giderse zaman aşımını kullanmaya çalıştım ve bunun asılı kaldığını keşfettim. Hangi timeouted versiyonu okuma yapmak başka iş parçacığı gerektiren yapar ...
Birkaç olasılık var:
stdout
.stderr
.stdin
.Başkalarının da bahsettiği gibi, stderr ve stdout tüketmelisiniz .
Diğer cevaplarla karşılaştırıldığında, Java 1.7'den beri daha da kolaydır. Artık stderr ve stdout okumak için kendi başınıza iş parçacıkları oluşturmanız gerekmiyor .
Sadece kullanın ProcessBuilder
ve yöntemleri veya redirectOutput
ile kombinasyon halinde kullanın .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();
Aynı nedenle, inheritIO()
Java konsolunu aşağıdaki gibi harici uygulama konsoluyla eşlemek için de kullanabilirsiniz :
ProcessBuilder pb = new ProcessBuilder(appPath, arguments);
pb.directory(new File(appFile.getParent()));
pb.inheritIO();
Process process = pb.start();
int success = process.waitFor();
Çıktı ve hatayı aynı anda tüketmeyi denemelisiniz
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");
}
Sanırım benzer bir sorun gözlemledim: bazı işlemler başladı, başarılı bir şekilde çalışıyor gibiydi ama hiç tamamlanmadı. WaitFor () işlevi, Görev Yöneticisi'ndeki işlemi sonlandırmam dışında sonsuza kadar bekliyordu.
Bununla birlikte, komut satırı uzunluğunun 127 karakter veya daha kısa olduğu durumlarda her şey yolunda gitti. Uzun dosya adları kaçınılmazsa, komut satırı dizesini kısa tutmanıza izin veren çevresel değişkenleri kullanmak isteyebilirsiniz. Gerçekten çalıştırmak istediğiniz programı çağırmadan önce çevresel değişkenlerinizi ayarladığınız bir toplu iş dosyası (FileWriter kullanarak) oluşturabilirsiniz. Böyle bir partinin içeriği şöyle görünebilir:
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%
Son adım, bu toplu iş dosyasını Runtime kullanarak çalıştırmaktır.
İşte benim için çalışan bir yöntem. NOT: Bu yöntemde sizin için geçerli olmayabilecek bazı kodlar vardır, bu yüzden deneyin ve görmezden gelin. Örneğin "logStandardOut (...), git-bash, vb."
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();
}
Zaman aşımıyla Beklemeyi önleme ile birlikte akışın zaman uyumsuz okuması sorunu çözecektir.
Bunu açıklayan bir sayfayı burada bulabilirsiniz http://simplebasics.net/.net/process-waitforexit-with-a-timeout-will-not-be-able-to-collect-the-output-message/