UPDATE: Ten artykuł został zastąpiony przez mój nowszy artykuł „Java exec z ProcessBuilder i Process”. Podczas gdy kod Java pokazany w tym tutorialu działa na prostych przypadkach „Java exec”, nowy artykuł pokazuje jak poprawnie odczytywać strumienie wyjściowe z komendy systemowej w wątkach Java, a także jak pisać na standardowe wejście komendy, jeśli to konieczne.

Nie krępuj się przeczytać tego artykułu dla tła/informacji o dziedzictwie, ale zdecydowanie zalecam użycie kodu źródłowego, który udostępniam w moim nowszym artykule „Java exec”, ponieważ rozwiązuje on problemy ze standardowym wejściem, wyjściem i błędami, których nie obsłużyłem poprawnie w poniższym kodzie.

Wprowadzenie

Czytałem dużo o Javie, ale jedną z rzeczy, którą rzadko widzę omawianą jest to, jak powinieneś przejść do uruchamiania zewnętrznych poleceń systemowych. Oczywiście, prawdopodobnie nie czytasz zbyt wiele na ten temat, ponieważ odbiera to przenośność aplikacji Java. Na przykład, jeśli piszesz aplikację Java na systemie Unix, możesz być zainteresowany uruchomieniem komendy „ps -ef” i przeczytaniem jej wyniku. Dla systemów uniksowych jest to świetne rozwiązanie, ale niestety, ten sam program nie będzie działał w systemie Windows, ponieważ polecenie ps nie jest dostępne w Windows.

Na potrzeby tego artykułu zapomnimy o przenośności i zademonstrujemy metodę, która może być użyta do uruchamiania poleceń systemowych. Otrzymaliśmy wiele próśb dotyczących tego tematu, więc zaczynamy.

Dyskusja (Runtime exec i Process)

Wykonanie polecenia systemowego jest stosunkowo proste – gdy już zobaczysz, jak to się robi za pierwszym razem. Polega na użyciu dwóch klas Javy, klasy Runtime i klasy Process. Zasadniczo, używasz metody exec klasy Runtime, aby uruchomić polecenie jako oddzielny proces. Wywołanie metody exec zwraca obiekt Process do zarządzania podprocesem. Następnie używasz metod getInputStream() i getErrorStream() obiektu Process do odczytania normalnego wyjścia polecenia i wyjścia błędu polecenia. To, co zrobisz z wyjściem wykonanego polecenia, zależy wyłącznie od ciebie i aplikacji, którą tworzysz.

(Uwaga: Istnieje również metoda getOutputStream(), której możesz użyć do zapisu do procesu, ale nie zajmiemy się nią w tym artykule. Zajmiemy się tym i kilkoma innymi zaawansowanymi funkcjami w przyszłym artykule.)

Przykład Java exec

Kod pokazany na Listingu 1 dostarcza działającego przykładu naszej techniki „Java exec” w pliku o nazwie JavaRunCommand.java.

import java.io.*;public class JavaRunCommand { public static void main(String args) { String s = null; try { // run the Unix "ps -ef" command // using the Runtime exec method: Process p = Runtime.getRuntime().exec("ps -ef"); BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream())); BufferedReader stdError = new BufferedReader(new InputStreamReader(p.getErrorStream())); // read the output from the command System.out.println("Here is the standard output of the command:\n"); while ((s = stdInput.readLine()) != null) { System.out.println(s); } // read any errors from the attempted command System.out.println("Here is the standard error of the command (if any):\n"); while ((s = stdError.readLine()) != null) { System.out.println(s); } System.exit(0); } catch (IOException e) { System.out.println("exception happened - here's what I know: "); e.printStackTrace(); System.exit(-1); } }}

Listing 1 (powyżej): Plik JavaRunCommand.java pokazuje, jak można uruchomić zewnętrzne polecenie systemowe z wnętrza programu Java.

Jak działa nasz kod Java exec

Pierwszą rzeczą, jaką robisz, jest określenie polecenia, które chcesz uruchomić, dostarczając to polecenie do klasy Runtime. Ponieważ nie możesz utworzyć własnej instancji klasy Runtime, najpierw używasz metody getRuntime, aby uzyskać dostęp do bieżącego środowiska uruchomieniowego, a następnie wywołujesz metodę exec klasy Runtime. Zwraca ona obiekt Process.

Wszystko inne, co robisz, angażuje metody obiektu Process. W tym przypadku, ponieważ wykonujemy komendę „ps -ef” w systemie Unix, musimy tylko odczytać wyjście komendy. Czytanie standardowego błędu prawdopodobnie nie jest wymagane w tym przypadku, ale pomyślałem, że przynajmniej warto to pokazać, jeśli nie jest to dobra praktyka programistyczna.

Konwertuję strumienie wejściowe za pomocą klas InputStreamReader i BufferedReader, więc mogę użyć metody readLine() klasy BufferedReader. Ponieważ używam tych klas, ta aplikacja nie skompiluje się poprawnie ze starszym kompilatorem JDK 1.0.x (te klasy nie były dostępne w 1.0.x).

Ściągnij przykładowy kod źródłowy „Java exec”

Mógłbym długo rozwodzić się na ten temat, ale najlepszą rzeczą, jaką mogę polecić, jest ściągnięcie kodu źródłowego i popracowanie z nim przez jakiś czas. Spróbuj uruchomić różne polecenia, aby zobaczyć, czy możesz uzyskać ich prawidłowe działanie, i spróbuj uruchomić polecenie, które wymaga danych wejściowych (to będzie trochę bardziej skomplikowane).