UPDATE: Ezt a cikket felváltotta az újabb “Java exec with ProcessBuilder and Process” című cikkem. Míg az ebben a bemutatóban bemutatott Java kód egyszerű “Java exec” esetekben működik, az új cikk bemutatja, hogyan kell megfelelően olvasni a rendszerparancs kimeneti folyamát Java szálakban, és azt is, hogyan kell írni a parancs standard bemenetére, ha szükséges.

Bátran olvassa el ezt a cikket a háttér/hagyományos információkért, de erősen ajánlom, hogy használja a forráskódot, amelyet az újabb “Java exec” cikkemben osztok meg, mert az megoldja a standard bemeneti, kimeneti és hibaproblémákat, amelyeket az alábbi kódban nem kezeltem megfelelően.

Bevezetés

Sokat olvastam a Java-ról, de az egyik dolog, amiről ritkán olvasok, az az, hogy hogyan kell a külső rendszerparancsokat futtatni. Persze valószínűleg azért nem sokat olvasol erről, mert ez elveszi a Java alkalmazások hordozhatóságát. Ha például egy Unix rendszeren írsz Java alkalmazást, akkor érdekelhet a “ps -ef” parancs futtatása, és a parancs kimenetének elolvasása. Unix rendszereken ez nagyszerű, de sajnos ugyanez a program nem fog működni egy Windows rendszeren, mert a ps parancs nem érhető el Windowson.

Nos, ebben a cikkben elfelejtjük a hordozhatóságot, és bemutatunk egy olyan módszert, amellyel a rendszerparancsok futtathatók. Rengeteg kérést kaptunk ezzel a témával kapcsolatban, úgyhogy íme.

Diszkusszió (Futásidejű végrehajtás és folyamat)

A rendszerparancs végrehajtása viszonylag egyszerű – ha egyszer már láttuk, hogy az első alkalommal megtörtént. Két Java osztály, a Runtime osztály és a Process osztály használatát foglalja magában. Alapvetően a Runtime osztály exec metódusát használjuk a parancs különálló folyamatként történő futtatásához. Az exec metódus meghívása egy Process objektumot ad vissza az alfolyamat kezeléséhez. Ezután a Process objektum getInputStream() és getErrorStream() metódusait használjuk a parancs normál kimenetének és a parancs hibakimenetének kiolvasására. Hogy mit csinálsz a végrehajtott parancs kimenetével, az teljesen rajtad és az általad létrehozott alkalmazáson múlik.

(Megjegyzés: Van egy getOutputStream() metódus is, amellyel írhatsz a processzbe, de ezzel a metódussal ebben a cikkben nem foglalkozunk. Ezzel és néhány más fejlett funkcióval egy későbbi cikkben foglalkozunk majd.)

Egy Java exec példa

Az 1. felsorolásban látható kód egy működő példát nyújt a “Java exec” technikánkhoz egy 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); } }}

Az 1. felsorolásban (fent) található fájlban: A JavaRunCommand.java fájl bemutatja, hogyan futtathatunk egy külső rendszerparancsot egy Java programból.

Hogyan működik a Java exec kódunk

Az első dolgunk, hogy megadjuk a futtatni kívánt parancsot, megadva ezt a parancsot a Runtime osztálynak. Mivel nem hozhatunk létre saját példányt a Runtime osztályból, először a getRuntime metódussal elérjük az aktuális futási környezetet, majd meghívjuk a Runtime exec metódust. Ez egy Process objektumot ad vissza.

Minden más, amit csinálsz, a Process objektum metódusait érinti. Ebben az esetben, mivel a “ps -ef” parancsot futtatjuk egy Unix rendszeren, csak a parancs kimenetét kell beolvasnunk. A standard hiba kiolvasása valószínűleg nem szükséges ebben az esetben, de úgy gondoltam, hogy legalább érdemes bemutatni, ha nem is jó programozási gyakorlat.

A bemeneti folyamokat az InputStreamReader és a BufferedReader segítségével alakítom át, hogy a BufferedReader osztály readLine() metódusát használhassam. Mivel ezeket az osztályokat használom, ez az alkalmazás nem fog megfelelően lefordítani egy régebbi JDK 1.0.x fordítóval (ezek az osztályok nem voltak elérhetők az 1.0.x-ben).

Töltse le a “Java exec” példa forráskódját

Hosszan tudnék még beszélni erről a témáról, de a legjobb, amit ajánlhatok, hogy töltse le a forráskódot, és dolgozzon vele egy darabig. Próbáljon meg különböző parancsokat futtatni, hogy lássa, megfelelően működnek-e, és próbáljon meg olyan parancsot futtatni, amely bemenetet igényel (ez egy kicsit bonyolultabb lesz).