UPDATE: Dit artikel is vervangen door mijn nieuwere “Java exec met ProcessBuilder en Process” artikel. Hoewel de Java-code in deze tutorial werkt voor eenvoudige “Java exec”-gevallen, laat het nieuwe artikel zien hoe je de uitvoerstromen van je systeemcommando op de juiste manier kunt lezen in Java-threads, en ook hoe je naar de standaardinvoer van je commando kunt schrijven, indien nodig.

Voel je vrij om dit artikel te lezen voor achtergrond/legacy informatie, maar ik raad je sterk aan om de broncode te gebruiken die ik deel in mijn nieuwere “Java exec” artikel, omdat het de standaard input, output, en error problemen oplost die ik niet goed heb afgehandeld in de code hieronder.

Inleiding

Ik heb veel over Java gelezen, maar een van de dingen die ik zelden besproken zie is hoe je te werk moet gaan bij het uitvoeren van externe systeemcommando’s. Natuurlijk lees je hier waarschijnlijk niet veel over omdat het afbreuk doet aan de portabiliteit van Java applicaties. Als je bijvoorbeeld een Java applicatie op een Unix systeem schrijft, zou je geïnteresseerd kunnen zijn in het uitvoeren van het “ps -ef” commando, en het lezen van de uitvoer van het commando. Voor Unix systemen is dit geweldig, maar helaas werkt ditzelfde programma niet op een Windows systeem, omdat het ps commando niet beschikbaar is op Windows.

Wel, we gaan portabiliteit vergeten voor dit artikel, en demonstreren een methode die kan worden gebruikt om systeem commando’s uit te voeren. We hebben veel verzoeken gekregen over dit onderwerp, dus hier gaan we.

Discussie (Runtime exec en Process)

Het uitvoeren van een systeemcommando is relatief eenvoudig – als je het eenmaal de eerste keer hebt zien doen. Er worden twee Java klassen voor gebruikt, de Runtime klasse en de Process klasse. In principe gebruik je de exec method van de Runtime class om de opdracht als een apart proces uit te voeren. Het aanroepen van de exec methode geeft een Process object voor het beheer van het subproces. Vervolgens gebruikt u de methoden getInputStream() en getErrorStream() van het object Process om de normale uitvoer van het commando te lezen, en de foutuitvoer van het commando. Wat je doet met de uitvoer van het uitgevoerde commando is geheel aan jou en de applicatie die je maakt.

(Opmerking: Er is ook een getOutputStream() methode die je kunt gebruiken om naar het proces te schrijven, maar die methode zullen we in dit artikel niet behandelen. We zullen die en een paar andere geavanceerde functies in een toekomstig artikel behandelen.)

Een Java exec voorbeeld

De code in Listing 1 geeft een werkend voorbeeld van onze “Java exec” techniek in een bestand met de naam 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 (hierboven): Het bestand JavaRunCommand.java laat zien hoe je een extern systeemcommando kunt uitvoeren vanuit een Java-programma.

Hoe onze Java exec code werkt

Het eerste wat je doet is het commando specificeren dat je wilt uitvoeren door dit commando aan de Runtime class te geven. Omdat u geen eigen instantie van de Runtime-klasse kunt maken, gebruikt u eerst de getRuntime-methode om toegang te krijgen tot de huidige runtime-omgeving en roept u vervolgens de Runtime exec-methode op. Dit retourneert een Process object.

Al het andere wat je doet heeft betrekking op methoden van het Process object. In dit geval, omdat we het “ps -ef” commando uitvoeren op een Unix systeem, hoeven we alleen maar de uitvoer van het commando te lezen. Het lezen van de standaard fout is waarschijnlijk niet nodig in dit geval, maar ik dacht dat het op zijn minst de moeite waard was om te laten zien, zo niet een goede programmeer praktijk.

Ik converteer de input streams met de InputStreamReader en BufferedReader, zodat ik de readLine() methode van de BufferedReader klasse kan gebruiken. Omdat ik deze klassen gebruik, zal deze applicatie niet goed compileren met een oudere JDK 1.0.x compiler (deze klassen waren niet beschikbaar in 1.0.x).

Download de “Java exec” voorbeeld broncode

Ik zou lang kunnen doorgaan over dit onderwerp, maar het beste wat ik kan aanraden is dat je de broncode download en er een tijdje mee werkt. Probeer verschillende commando’s uit te voeren om te zien of u ze naar behoren kunt laten werken, en probeer een commando uit te voeren dat invoer vereist (dit zal een beetje ingewikkelder zijn).