OPDATERING: Denne artikel er blevet erstattet af min nyere artikel “Java exec with ProcessBuilder and Process”. Mens den Java-kode, der er vist i denne vejledning, fungerer i simple “Java exec”-tilfælde, viser den nye artikel, hvordan du korrekt læser outputstreams fra din systemkommando i Java-tråde, og også hvordan du om nødvendigt skriver til din kommandos standardinput.

Føler dig velkommen til at læse denne artikel for at få baggrunds-/legacy-informationer, men jeg anbefaler på det kraftigste, at du bruger kildekoden, som jeg deler i min nyere “Java exec”-artikel, fordi den løser de problemer med standard input, output og fejl, som jeg ikke håndterede korrekt i koden nedenfor.

Indledning

Jeg har læst meget om Java, men en af de ting, jeg sjældent ser diskuteret, er, hvordan du skal gå til at køre eksterne systemkommandoer. Selvfølgelig læser du sikkert ikke meget om dette, fordi det går ud over portabiliteten af Java-programmer. Hvis du f.eks. skriver en Java-applikation på et Unix-system, vil du måske være interesseret i at køre kommandoen “ps -ef” og læse resultatet af kommandoen. For Unix-systemer er det fint, men desværre vil det samme program ikke fungere på et Windows-system, fordi ps-kommandoen ikke er tilgængelig på Windows.

Nå, men vi vil glemme portabiliteten i denne artikel og demonstrere en metode, der kan bruges til at køre systemkommandoer. Vi har modtaget mange forespørgsler om dette emne, så her kommer det.

Diskussion (Runtime exec og Process)

Afvikling af en systemkommando er relativt simpelt – når først man har set det gjort første gang. Det indebærer brug af to Java-klasser, Runtime-klassen og Process-klassen. Dybest set bruger du metoden exec i Runtime-klassen til at køre kommandoen som en separat proces. Ved at påkalde exec-metoden returneres et Process-objekt til forvaltning af underprocessen. Derefter bruger du getInputStream()– og getErrorStream()-metoderne i Process-objektet til at læse det normale output af kommandoen og fejloutput af kommandoen. Hvad du gør med output af den udførte kommando, er helt op til dig og det program, du opretter.

(Bemærk: Der findes også en getOutputStream()-metode, som du kan bruge til at skrive til processen, men den metode vil vi ikke behandle i denne artikel. Vi vil dække den og et par andre avancerede funktioner i en fremtidig artikel.)

Et eksempel på Java exec

Koden vist i Listing 1 giver et fungerende eksempel på vores “Java exec”-teknik i en fil med navnet 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 (ovenfor): Filen JavaRunCommand.java viser, hvordan du kan køre en ekstern systemkommando fra et Java-program.

Sådan fungerer vores Java exec-kode

Den første ting, du gør, er at angive den kommando, du vil køre, ved at levere denne kommando til Runtime-klassen. Da du ikke kan oprette din egen instans af Runtime-klassen, bruger du først getRuntime-metoden til at få adgang til det aktuelle kørselstidsmiljø og derefter til at påkalde Runtime exec-metoden. Denne returnerer et Process-objekt.

Alt andet, du gør, involverer metoder fra Process-objektet. I dette tilfælde, fordi vi kører kommandoen “ps -ef” på et Unix-system, skal vi blot læse resultatet af kommandoen. Det er nok ikke nødvendigt at læse standardfejlen i dette tilfælde, men jeg tænkte, at det i det mindste var værd at vise, om ikke god programmeringspraksis.

Jeg konverterer inputstrømmene med InputStreamReader og BufferedReader, så jeg kan bruge readLine()-metoden i BufferedReader-klassen. Fordi jeg bruger disse klasser, vil dette program ikke kompilere korrekt med en ældre JDK 1.0.x-compiler (disse klasser var ikke tilgængelige i 1.0.x).

Download kildekoden til “Java exec”-eksemplet

Jeg kunne blive ved med at tale længe om dette emne, men det bedste, jeg kan anbefale, er, at du downloader kildekoden og arbejder med den i et stykke tid. Prøv at køre forskellige kommandoer for at se, om du kan få dem til at fungere korrekt, og prøv at køre en kommando, der kræver input (dette vil være lidt mere kompliceret).