ProcessBuilder類是J2SE 1.5在java.lang中新添加的一個新類,此類用于建立作業系統程序,它提供一種啟動和管理程序(也就是應用程式)的方法。在J2SE 1.5之前,都是由Process類處來實作程序的控制管理。每個 ProcessBuilder 執行個體管理一個程序屬性集。它的start() 方法利用這些屬性建立一個新的 Process 執行個體。start() 方法可以從同一執行個體重複調用,以利用相同的或相關的屬性建立新的子程序。
每個程序生成器(即ProcessBuilder對象)管理這些程序屬性:
指令 command
是一個字元串清單,它表示要調用的外部程式檔案及其參數(如果有)。在此,表示有效的作業系統指令的字元串清單是依賴于系統的。例如,每一個總體變量,通常都要成為此清單中的元素,但有一些作業系統,希望程式能自己标記指令行字元串——在這種系統中,Java 實作可能需要指令确切地包含這兩個元素。
環境 environment
是從變量 到值 的依賴于系統的映射。初始值是目前程序環境的一個副本(請參閱 System.getenv())。
工作目錄 working directory
預設值是目前程序的目前工作目錄,通常根據系統屬性 user.dir 來命名。
redirectErrorStream屬性
最初,此屬性為 false,意思是子程序的标準輸出和錯誤輸出被發送給兩個獨立的流,這些流可以通過 Process.getInputStream() 和 Process.getErrorStream() 方法來通路。如果将值設定為 true,标準錯誤将與标準輸出合并。這使得關聯錯誤消息和相應的輸出變得更容易。在此情況下,合并的資料可從 Process.getInputStream() 傳回的流讀取,而從 Process.getErrorStream() 傳回的流讀取将直接到達檔案尾。
既然有Process類,那為什麼還要發明個ProcessBuilder類呢?ProcessBuilder和Process兩個類有什麼差別呢?
原來,ProcessBuilder為程序提供了更多的控制,例如,可以設定目前工作目錄,還可以改變環境參數。而Process的功能相對來說簡單的多。
ProcessBuilder是一個final類,有兩個帶參數的構造方法,你可以通過構造方法來直接建立ProcessBuilder的對象。而Process是一個抽象類,一般都通過Runtime.exec()和ProcessBuilder.start()來間接建立其執行個體。(有關Process類的詳細介紹可以看下一節。)
修改程序構造器的屬性将影響後續由該對象的 start() 方法啟動的程序,但從不會影響以前啟動的程序或 Java 自身的程序。 ProcessBuilder類不是同步的。如果多個線程同時通路一個 ProcessBuilder,而其中至少一個線程從結構上修改了其中一個屬性,它必須 保持外部同步。
很容易啟動一個使用預設工作目錄和環境的新程序:(沿用JDK7中的例子)
下面是一個利用修改過的工作目錄和環境啟動程序的例子:
要利用一組明确的環境變量啟動程序,在添加環境變量之前,首先調用 Map.clear()。
Process類是一個抽象類(所有的方法均是抽象的),封裝了一個程序(即一個執行程式)。
Process 類提供了執行從程序輸入、執行輸出到程序、等待程序完成、檢查程序的退出狀态以及銷毀(殺掉)程序的方法。建立程序的方法可能無法針對某些本機平台上的特定程序很好地工作,比如,本機視窗程序,守護程序,Microsoft Windows 上的 Win16/DOS 程序,或者 shell 腳本。建立的子程序沒有自己的終端或控制台。它的所有标準 io(即 stdin、stdout 和 stderr)操作都将通過三個流 (getOutputStream()、getInputStream() 和 getErrorStream()) 重定向到父程序。父程序使用這些流來提供到子程序的輸入和獲得從子程序的輸出。因為有些本機平台僅針對标準輸入和輸出流提供有限的緩沖區大小,如果讀寫子 程序的輸出流或輸入流迅速出現失敗,則可能導緻子程序阻塞,甚至産生死鎖。 當沒有 Process 對象的更多引用時,不是删掉子程序,而是繼續異步執行子程序。 對于帶有 Process 對象的 Java 程序,沒有必要異步或并發執行由 Process 對象表示的程序。
Process抽象類有以下6個抽象方法:
destroy()
殺掉子程序。
exitValue()
傳回子程序的出口值。
InputStream getErrorStream()
獲得子程序的錯誤流。
InputStream getInputStream()
獲得子程序的輸入流。
OutputStream getOutputStream()
獲得子程序的輸出流。
waitFor()
導緻目前線程等待,如果必要,一直要等到由該 Process 對象表示的程序已經終止。
如何建立Process對象?
一般有兩種方法:
使用指令名和指令的參數選項構造ProcessBuilder對象,它的start方法執行指令,啟動一個程序,傳回一個Process對象。
Runtime.exec() 方法建立一個本機程序,并傳回 Process 子類的一個執行個體。
ProcessBuilder與Runtime.exec()的差別?
ProcessBuilder.start() 和 Runtime.exec() 方法都被用來建立一個作業系統程序(執行指令行操作),并傳回 Process 子類的一個執行個體,該執行個體可用來控制程序狀态并獲得相關資訊。
ProcessBuilder.start() 和 Runtime.exec()傳遞的參數有所不同,Runtime.exec()可接受一個單獨的字元串,這個字元串是通過空格來分隔可執行指令程式和參數的;也可以接受字元串數組參數。而ProcessBuilder的構造函數是一個字元串清單或者數組。清單中第一個參數是可執行指令程式,其他的是指令行執行是需要的參數。
通過檢視JDK源碼可知,Runtime.exec最終是通過調用ProcessBuilder來真正執行操作的。
為了能夠詳細的說明ProcessBuilder和Runtime.exec的“功效”,下面先做一個測試jar包(ProcessJar.jar),這個jar包裡就一個類,如下:
然後放在classpath下。之後可以調用指令行:java -jar ProcessJar.jar [args1….n]
Runtime.getRuntime.exec的使用Demo:
輸出結果:
由于調用Runtime.exec方法所建立的子程序沒有自己的終端或控制台,是以該子程序的标準IO(如stdin,stdou,stderr)都通過Process.getOutputStream(),Process.getInputStream(),Process.getErrorStream()方法重定向給它的父程序了。使用者需要用這些stream來向子程序輸入資料或擷取子程序的輸出。
構造方法摘要
ProcessBuilder(List<String> command)
利用指定的作業系統程式和參數構造一個程序生成器。
ProcessBuilder(String… command)
方法摘要
command()
傳回此程序生成器的作業系統程式和參數。
command(List<String> command)
設定此程序生成器的作業系統程式和參數。
command(String… command)
directory()
傳回此程序生成器的工作目錄。
directory(File directory)
設定此程序生成器的工作目錄。
environment()
傳回此程序生成器環境的字元串映射視圖。 environment方法獲得運作程序的環境變量,得到一個Map,可以修改環境變量
redirectErrorStream()
通知程序生成器是否合并标準錯誤和标準輸出。
redirectErrorStream(boolean redirectErrorStream)
設定此程序生成器的 redirectErrorStream 屬性。
start()
使用此程序生成器的屬性啟動一個新程序。
這裡示範一個ProcessBuilder的demo,和Runtime.exec()方法差不多,同樣是采用ProcessJar.jar進行測試。
為了更形象的說明ProcessBuilder的用法,下面再舉幾個例子: