UPDATE: Tämä artikkeli on korvattu uudemmalla artikkelillani ”Java exec with ProcessBuilder and Process”. Vaikka tässä ohjeessa esitetty Java-koodi toimii yksinkertaisissa ”Java exec” -tapauksissa, uusi artikkeli näyttää, miten järjestelmäkomennon tulostusvirrat luetaan oikein Java-säikeissä ja miten komennon vakiotuloon kirjoitetaan tarvittaessa.

Lue rohkeasti tämä artikkeli taustatietoa/perintötietoa varten, mutta suosittelen lämpimästi käyttämään lähdekoodia, jonka jaan uudemmassa ”Java exec” -artikkelissani, koska se ratkaisee standarditulo-, -lähtö- ja -virheongelmat, joita en käsitellyt kunnolla alla olevassa koodissa.

Esittely

Olen lukenut paljon Javasta, mutta yksi harvoin käsittelemäni asia on se, miten ulkoisten järjestelmäkomentojen suorittaminen kannattaa tehdä. Tästä ei tietenkään luultavasti lueta paljon, koska se vie Java-sovellusten siirrettävyyttä. Jos esimerkiksi kirjoitat Java-sovellusta Unix-järjestelmässä, saatat olla kiinnostunut suorittamaan komennon ”ps -ef” ja lukemaan komennon tulosteen. Unix-järjestelmissä tämä on hienoa, mutta valitettavasti sama ohjelma ei toimi Windows-järjestelmässä, koska ps-komento ei ole käytettävissä Windowsissa.

No, unohdamme siirrettävyyden tämän artikkelin ajaksi ja esittelemme menetelmän, jota voidaan käyttää järjestelmän komentojen suorittamiseen. Olemme saaneet paljon pyyntöjä tästä aiheesta, joten tässä sitä mennään.

Keskustelu (Runtime exec and Process)

Järjestelmäkomennon suorittaminen on suhteellisen yksinkertaista – kunhan olet nähnyt, miten se tehdään ensimmäisen kerran. Siihen liittyy kahden Java-luokan, Runtime-luokan ja Process-luokan, käyttö. Periaatteessa käytät Runtime-luokan exec-metodia komennon suorittamiseen erillisenä prosessina. exec-metodin kutsuminen palauttaa Process-olion aliprosessin hallintaa varten. Sitten käytät Process-olion getInputStream()– ja getErrorStream()-metodeja komennon normaalin tulosteen ja komennon virhetulosteen lukemiseen. Se, mitä teet suoritetun komennon tulosteella, riippuu täysin sinusta ja luomastasi sovelluksesta.

(Huomautus: On myös getOutputStream()-metodi, jolla voit kirjoittaa prosessiin, mutta emme käsittele sitä tässä artikkelissa. Käsittelemme sitä ja muutamia muita kehittyneitä ominaisuuksia tulevassa artikkelissa.)

Esimerkki Java exec:stä

Listauksessa 1 esitetty koodi tarjoaa toimivan esimerkin ”Java exec”-tekniikastamme tiedostossa nimeltä 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); } }}

Listaus 1 (yllä): Tiedosto JavaRunCommand.java näyttää, miten voit suorittaa ulkoisen järjestelmäkomennon Java-ohjelmasta käsin.

Miten meidän Java exec -koodimme toimii

Aluksi määrittelet komennon, jonka haluat suorittaa, antamalla tämän komennon Runtime-luokkaan. Koska et voi luoda omaa instanssia Runtime-luokasta, käytät ensin getRuntime-metodia päästäksesi käsiksi nykyiseen ajoympäristöön ja kutsut sitten Runtime exec-metodia. Tämä palauttaa Process-olion.

Kaikkeen muuhun tekemääsi liittyy Process-olion metodeja. Tässä tapauksessa, koska suoritamme komennon ”ps -ef” Unix-järjestelmässä, meidän on vain luettava komennon tulosteet. Vakiovirheen lukemista ei luultavasti tarvita tässä tapauksessa, mutta ajattelin, että se on ainakin näyttämisen arvoista, jos ei hyvää ohjelmointitapaa.

Muunnan InputStreamReader- ja BufferedReader-luokilla tulovirrat niin, että voin käyttää BufferedReader-luokan readLine()-metodia. Koska käytän näitä luokkia, tämä sovellus ei käänny kunnolla vanhemmalla JDK 1.0.x -kääntäjällä (näitä luokkia ei ollut saatavilla 1.0.x:ssä).

Lataa ”Java exec” -esimerkin lähdekoodi

Voisin puhua pitkään tästä aiheesta, mutta paras mitä voin suositella on, että lataat lähdekoodin ja työskentelet sen kanssa jonkin aikaa. Kokeile erilaisten komentojen suorittamista nähdäksesi, saatko ne toimimaan kunnolla, ja yritä suorittaa komento, joka vaatii syötettä (tämä on hieman monimutkaisempaa).