Process process = Runtime.getRuntime().exec("tasklist");
BufferedReader reader =
new BufferedReader(new InputStreamReader(process.getInputStream()));
process.waitFor();
java
runtime.exec
user590444
źródło
źródło
Odpowiedzi:
Istnieje wiele powodów, które
waitFor()
nie wracają.Ale zwykle sprowadza się to do tego, że wykonywane polecenie nie kończy się.
To znowu może mieć wiele powodów.
Jednym z typowych powodów jest to, że proces generuje pewne dane wyjściowe, a Ty nie czytasz z odpowiednich strumieni. Oznacza to, że proces jest blokowany, gdy tylko bufor się zapełni i czeka, aż proces będzie kontynuował czytanie. Twój proces z kolei czeka na zakończenie drugiego procesu (co nie nastąpi, ponieważ czeka na Twój proces, ...). To jest klasyczna sytuacja impasu.
Musisz stale czytać ze strumienia wejściowego procesów, aby upewnić się, że nie blokuje.
Jest fajny artykuł, który wyjaśnia wszystkie pułapki
Runtime.exec()
i pokazuje sposoby ich obejścia, nazwany „Kiedy Runtime.exec () nie będzie” (tak, artykuł pochodzi z 2000 roku, ale treść nadal obowiązuje!)źródło
waitFor()
nie zwraca.Wygląda na to, że nie czytasz wyjścia, zanim zaczekasz na jego zakończenie. Jest to dobre tylko wtedy, gdy dane wyjściowe nie wypełniają bufora. Jeśli tak, będzie czekać, aż odczytasz wyjście, catch-22.
Być może masz jakieś błędy, których nie czytasz. Spowodowałoby to zatrzymanie aplikacji i czekanie na wieczne oczekiwanie. Prostym sposobem obejścia tego jest przekierowanie błędów do zwykłego wyjścia.
źródło
pb.redirectError(new File("/dev/null"));
redirectError
jest dostępna tylko od wersji Java 1.7Również z dokumentu Java:
Spróbuj tego:
źródło
DefaultExecutor executor = new DefaultExecutor(); PumpStreamHandler pumpStreamHandler = new PumpStreamHandler(stdoutOS, stderrOS); executor.setStreamHandler(pumpStreamHandler); executor.execute(cmdLine);
gdzie stoutOS i stderrOS toBufferedOutputStream
s, które stworzyłem, aby wypisywać do odpowiednich plików.process.close()
. Ale kiedy otwieram strumień wejściowy zgodnie z powyższą sugestią i natychmiast zamykam - problem znika. Więc w moim przypadku Wiosna czekała na sygnał zamknięcia strumienia. Mimo że używam automatycznego zamykania Java 8.Chciałbym coś dodać do poprzednich odpowiedzi, ale ponieważ nie mam przedstawiciela do komentowania, po prostu dodam odpowiedź. Jest to skierowane do użytkowników Androida, którzy programują w języku Java.
Zgodnie z postem od RollingBoy, ten kod prawie działał dla mnie:
W moim przypadku funkcja waitFor () nie była zwalniana, ponieważ wykonywałem instrukcję bez powrotu („ip adddr flush eth0”). Łatwym sposobem naprawienia tego jest po prostu upewnienie się, że zawsze zwracasz coś w wyciągu. Dla mnie oznaczało to wykonanie następującego polecenia: "ip adddr flush eth0 && echo done". Możesz czytać bufor przez cały dzień, ale jeśli nic nie zostanie zwrócone, Twój wątek nigdy nie zwolni swojego oczekiwania.
Mam nadzieję, że to komuś pomoże!
źródło
process.waitFor()
zawiesza, ale to sięreader.readLine()
zawiesza, jeśli nie masz wyjścia. Próbowałem użyćwaitFor(long,TimeUnit)
limitu czasu, jeśli coś pójdzie nie tak i odkryłem, że był to odczyt zawieszony. Co sprawia, że wersja z przekroczonym limitem czasu wymaga innego wątku do wykonania odczytu ...Możliwości jest kilka:
stdout
.stderr
.stdin
.źródło
Jak wspominali inni, musisz używać stderr i stdout .
W porównaniu z innymi odpowiedziami, ponieważ Java 1.7 jest jeszcze łatwiejsza. Nie musisz już samodzielnie tworzyć wątków, aby czytać stderr i stdout .
Po prostu użyj
ProcessBuilder
i użyj tych metodredirectOutput
w połączeniu z alboredirectError
lubredirectErrorStream
.źródło
Z tego samego powodu możesz również użyć
inheritIO()
do mapowania konsoli Java z zewnętrzną konsolą aplikacji, na przykład:źródło
Powinieneś spróbować zużyć wyjście i błąd w tym samym czasie
źródło
Myślę, że zauważyłem podobny problem: niektóre procesy rozpoczęły się, wydawały się działać pomyślnie, ale nigdy nie zostały zakończone. Funkcja waitFor () czekała wiecznie, chyba że zabiłem proces w Menedżerze zadań.
Jednak wszystko działało dobrze w przypadkach, gdy długość wiersza poleceń wynosiła 127 znaków lub mniej. Jeśli długie nazwy plików są nieuniknione, możesz chcieć użyć zmiennych środowiskowych, które mogą pozwolić ci zachować krótki ciąg wiersza poleceń. Możesz wygenerować plik wsadowy (za pomocą FileWriter), w którym ustawiasz zmienne środowiskowe przed wywołaniem programu, który chcesz uruchomić. Zawartość takiej partii mogłaby wyglądać następująco:
Ostatnim krokiem jest uruchomienie tego pliku wsadowego przy użyciu środowiska wykonawczego.
źródło
Oto metoda, która działa dla mnie. UWAGA: W tej metodzie jest kod, który może nie mieć zastosowania, więc spróbuj go zignorować. Na przykład „logStandardOut (...), git-bash itp.”.
}
źródło
Asynchroniczne odczytywanie strumienia połączone z unikaniem czekania z przekroczeniem limitu czasu rozwiąże problem.
Możesz znaleźć stronę wyjaśniającą to tutaj http://simplebasics.net/.net/process-waitforexit-with-a-timeout-will-not-be-able-to-collect-the-output-message/
źródło