Veiledning til java.lang.ProcessBuilder API

1. Oversikt

Prosess-API-en gir en kraftig måte å utføre operativsystemkommandoer på Java. Imidlertid har den flere alternativer som kan gjøre det tungvint å jobbe med.

I denne veiledningen, Vi tar en titt på hvordan Java lindrer det med ProcessBuilder API.

2. ProcessBuilder API

De ProcessBuilder klasse gir metoder for å lage og konfigurere operativsystemprosesser. Hver ProcessBuilder eksempel lar oss administrere en samling prosessattributter. Vi kan da starte en ny Prosess med de gitte attributtene.

Her er noen vanlige scenarier der vi kan bruke dette API:

  • Finn den gjeldende Java-versjonen
  • Sett opp et tilpasset nøkkelverdikart for miljøet vårt
  • Endre arbeidskatalogen for hvor shell-kommandoen kjører
  • Viderekoble inngangs- og utgangsstrømmer til tilpassede erstatninger
  • Arv begge strømmer av den nåværende JVM-prosessen
  • Utfør en skallkommando fra Java-kode

Vi tar en titt på praktiske eksempler for hver av disse i senere seksjoner.

Men før vi dykker inn i arbeidskoden, la oss ta en titt på hva slags funksjonalitet denne APIen gir.

2.1. Metodesammendrag

I denne seksjonen, vi skal ta et skritt tilbake og kort se på de viktigste metodene i ProcessBuilder klasse. Dette vil hjelpe oss når vi dykker ned i noen reelle eksempler senere:

  • ProcessBuilder (streng ... kommando)

    For å lage en ny prosessbygger med det angitte operativsystemprogrammet og argumentene, kan vi bruke denne praktiske konstruktøren.

  • katalog (Filkatalog)

    Vi kan overstyre standard arbeidskatalog for den nåværende prosessen ved å ringe katalog metode og bestått en Fil gjenstand. Som standard er den nåværende arbeidskatalogen satt til verdien som returneres av bruker.dir systemegenskap.

  • miljø()

    Hvis vi ønsker å få de gjeldende miljøvariablene, kan vi ganske enkelt ringe miljø metode. Det gir oss en kopi av det nåværende prosessmiljøet ved hjelp av System.getenv () men som en Kart .

  • inheritIO ()

    Hvis vi ønsker å spesifisere at kilden og destinasjonen for vår underprosess standard I / O skal være den samme som den gjeldende Java-prosessen, kan vi bruke arv metode.

  • redirectInput (filfil), redirectOutput (filfil), redirectError (filfil)

    Når vi vil omdirigere prosessbyggerens standardinndata, utdata og feilmål til en fil, har vi disse tre lignende omdirigeringsmetodene til rådighet.

  • start()

    Sist men ikke minst, for å starte en ny prosess med det vi har konfigurert, kaller vi bare start().

Vi bør merke oss at denne klassen IKKE er synkronisert. For eksempel hvis vi har flere tråder som får tilgang til a ProcessBuilder forekomst samtidig må synkroniseringen administreres eksternt.

3. Eksempler

Nå som vi har en grunnleggende forståelse av ProcessBuilder API, la oss gå gjennom noen eksempler.

3.1. Ved hjelp av ProcessBuilder for å skrive ut versjonen av Java

I dette første eksemplet kjører vi java kommando med ett argument for å få versjonen.

Prosessprosess = ny ProcessBuilder ("java", "-versjon"). Start ();

Først lager vi vårt ProcessBuilder objekt som sender kommando- og argumentverdiene til konstruktøren. Deretter starter vi prosessen med start() metode for å få en Prosess gjenstand.

La oss nå se hvordan vi skal håndtere utdataene:

Listeresultater = readOutput (process.getInputStream ()); assertThat ("Resultatene skal ikke være tomme", resultater, er (ikke (tomme ()))); assertThat ("Resultatene skal inneholde java-versjon:", resultater, hasItem (inneholderString ("java-versjon"))); int exitCode = process.waitFor (); assertEquals ("Ingen feil skal oppdages", 0, exitCode);

Her leser vi prosessutdataene og verifiserer innholdet som vi forventer. I siste trinn venter vi på at prosessen skal være ferdig process.waitFor ().

Når prosessen er ferdig, forteller returverdien oss om prosessen var vellykket eller ikke.

Noen viktige punkter å huske på:

  • Argumentene må være i riktig rekkefølge
  • Videre brukes i dette eksemplet standard arbeidskatalog og miljø
  • Vi ringer bevisst ikke process.waitFor () til etter at vi har lest utdataene fordi utgangsbufferen kan stoppe prosessen
  • Vi har antatt at java kommandoen er tilgjengelig via STI variabel

3.2. Starte en prosess med et modifisert miljø

I dette neste eksemplet skal vi se hvordan du kan endre arbeidsmiljøet.

Men før vi gjør det, la oss begynne med å se på hva slags informasjon vi kan finne i standardmiljøet:

ProcessBuilder processBuilder = ny ProcessBuilder (); Kartmiljø = processBuilder.environment (); environment.forEach ((nøkkel, verdi) -> System.out.println (nøkkel + verdi));

Dette skriver ganske enkelt ut hver av variabeloppføringene som er gitt som standard:

PATH / usr / bin: / bin: / usr / sbin: / sbin SHELL / bin / bash ...

Nå skal vi legge til en ny miljøvariabel i vår ProcessBuilder objekt og kjør en kommando for å sende ut verdien:

environment.put ("Hilsen", "Hola Mundo"); processBuilder.command ("/ bin / bash", "-c", "echo $ GREETING"); Prosessprosess = processBuilder.start ();

La oss nedbryte trinnene for å forstå hva vi har gjort:

  • Legg til en variabel kalt 'GREETING' med verdien 'Hola Mundo' i miljøet vårt, som er en standard Kart
  • Denne gangen, i stedet for å bruke konstruktøren, setter vi kommandoen og argumentene via kommando (streng ... kommando) metode direkte.
  • Vi starter deretter prosessen i henhold til forrige eksempel.

For å fullføre eksemplet, bekrefter vi at utdataene inneholder hilsenen:

Liste resultater = readOutput (process.getInputStream ()); assertThat ("Resultatene skal ikke være tomme", resultater, er (ikke (tomme ()))); assertThat ("Resultatene skal inneholde java-versjon:", resultater, hasItem (inneholderString ("Hola Mundo")));

3.3. Starte en prosess med en modifisert arbeidskatalog

Noen ganger kan det være nyttig å endre arbeidskatalogen. I vårt neste eksempel skal vi se hvordan vi kan gjøre nettopp det:

@Test offentlig ugyldig givenProcessBuilder_whenModifyWorkingDir_thenSuccess () kaster IOException, InterruptedException {ProcessBuilder processBuilder = ny ProcessBuilder ("/ bin / sh", "-c", "ls"); processBuilder.directory (ny fil ("src")); Prosessprosess = processBuilder.start (); Liste resultater = readOutput (process.getInputStream ()); assertThat ("Resultatene skal ikke være tomme", resultater, er (ikke (tomme ()))); assertThat ("Resultatene skal inneholde katalogoppføring:", resultater, inneholder ("hoved", "test")); int exitCode = process.waitFor (); assertEquals ("Ingen feil skal oppdages", 0, exitCode); }

I eksemplet ovenfor setter vi arbeidskatalogen til prosjektet src dir ved hjelp av bekvemmelighetsmetoden katalog (Filkatalog). Vi kjører deretter en enkel katalogoppføringskommando og sjekker at utdataene inneholder underkatalogene hoved- og test.

3.4. Omdirigering av standard inngang og utgang

I den virkelige verden vil vi sannsynligvis ønske å fange resultatene av våre kjørende prosesser i en loggfil for videre analyse. Heldigvis ProcessBuilder API har innebygd støtte for akkurat dette som vi vil se i dette eksemplet.

Som standard leser prosessen innspill fra et rør. Vi kan få tilgang til dette røret via utgangsstrømmen som returneres av Process.getOutputStream ().

Imidlertid, som vi snart vil se, kan standardutdataene omdirigeres til en annen kilde, for eksempel en fil ved hjelp av metoden redirectOutput. I dette tilfellet, getOutputStream () vil returnere en ProcessBuilder.NullOutputStream.

La oss gå tilbake til vårt opprinnelige eksempel for å skrive ut versjonen av Java. Men la oss denne gangen omdirigere utdata til en loggfil i stedet for standard utgangsrør:

ProcessBuilder processBuilder = ny ProcessBuilder ("java", "-versjon"); processBuilder.redirectErrorStream (true); Fillogg = folder.newFile ("java-version.log"); processBuilder.redirectOutput (logg); Prosessprosess = processBuilder.start ();

I eksemplet ovenfor, vi oppretter en ny midlertidig fil som heter logg og forteller vår ProcessBuilder for å omdirigere utdata til denne fildestinasjonen.

I dette siste utdraget sjekker vi det bare getInputStream () er absolutt null og at innholdet i filen vår er som forventet:

assertEquals ("Hvis omdirigert, skal være -1", -1, process.getInputStream (). les ()); Liste linjer = Files.lines (log.toPath ()). Samle (Collectors.toList ()); assertThat ("Resultatene skal inneholde Java-versjon:", linjer, hasItem (inneholderString ("Java-versjon")));

La oss nå se på en liten variasjon i dette eksemplet. For eksempel når vi ønsker å legge til en loggfil i stedet for å opprette en ny hver gang:

Fillogg = tempFolder.newFile ("java-version-append.log"); processBuilder.redirectErrorStream (true); processBuilder.redirectOutput (Redirect.appendTo (log));

Det er også viktig å nevne samtalen til redirectErrorStream (true). I tilfelle feil, blir feilutdata slått sammen til normal prosessutdatafil.

Vi kan selvfølgelig spesifisere individuelle filer for standardutdata og standardfeilutdata:

File outputLog = tempFolder.newFile ("standard-output.log"); Fil errorLog = tempFolder.newFile ("error.log"); processBuilder.redirectOutput (Redirect.appendTo (outputLog)); processBuilder.redirectError (Redirect.appendTo (errorLog));

3.5. Arve I / U av den nåværende prosessen

I dette nest siste eksemplet ser vi inheritIO () metode i aksjon. Vi kan bruke denne metoden når vi vil omdirigere delprosess I / O til standard I / O for den nåværende prosessen:

@Test offentlig ugyldig givenProcessBuilder_whenInheritIO_thenSuccess () kaster IOException, InterruptedException {ProcessBuilder processBuilder = ny ProcessBuilder ("/ bin / sh", "-c", "echo hallo"); processBuilder.inheritIO (); Prosessprosess = processBuilder.start (); int exitCode = process.waitFor (); assertEquals ("Ingen feil skal oppdages", 0, exitCode); }

I eksemplet ovenfor bruker du inheritIO () metoden ser vi utdataene fra en enkel kommando i konsollen i IDE.

I neste avsnitt skal vi se på hvilke tillegg som ble gjort i ProcessBuilder API i Java 9.

4. Java 9-tillegg

Java 9 introduserte begrepet rørledninger til ProcessBuilder API:

public static List startPipeline (List builders) 

Bruker startPipeline metoden vi kan sende en liste over ProcessBuilder gjenstander. Denne statiske metoden starter deretter a Prosess for hver ProcessBuilder. Dermed oppretter en rørledning av prosesser som er koblet sammen med deres standardutgang og standard inngangsstrømmer.

For eksempel hvis vi vil kjøre noe slikt:

finne. -navn * .java -type f | wc -l

Hva vi vil gjøre er å lage en prosessbygger for hver isolerte kommando og komponere dem i en rørledning:

@Test offentlig ugyldig givenProcessBuilder_whenStartingPipeline_thenSuccess () kaster IOException, InterruptedException {List builders = Arrays.asList (new ProcessBuilder ("find", "src", "-name", "* .java", "-type", "f") , ny ProcessBuilder ("wc", "-l")); Listeprosesser = ProcessBuilder.startPipeline (byggere); Prosess siste = prosesser.get (prosesser.størrelse () - 1); Listeutgang = readOutput (last.getInputStream ()); assertThat ("Resultatene skal ikke være tomme", output, er (ikke (tom ()))); }

I dette eksemplet søker vi etter alle java-filene i src katalog og rør resultatene i en annen prosess for å telle dem.

For å lære om andre forbedringer som er gjort med prosess-API i Java 9, kan du sjekke ut vår flotte artikkel om forbedringer av Java 9-prosess-API.

5. Konklusjon

For å oppsummere har vi i denne veiledningen utforsket java.lang.ProcessBuilder API i detalj.

Først startet vi med å forklare hva som kan gjøres med API og oppsummerte de viktigste metodene.

Deretter tok vi en titt på en rekke praktiske eksempler. Til slutt så vi på hvilke nye tillegg som ble introdusert til API i Java 9.

Som alltid er hele kildekoden til artikkelen tilgjengelig på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found