浅析Java.lang.ProcessBuilder类
? ? ? ?最近由于工作需要把用戶配置的Hive命令在Linux環境下執行,專門做了一個用戶管理界面特地研究了這個不經常用得ProcessBuilder類。所以把自己的學習的資料總結一下。
? ? ? ??
一、概述
????? ProcessBuilder類是J2SE 1.5在java.lang中新添加的一個新類,此類用于創建操作系統進程,它提供一種啟動和管理進程(也就是應用程序)的方法。在J2SE 1.5之前,都是由Process類處來實現進程的控制管理。
????? 每個 ProcessBuilder 實例管理一個進程屬性集。它的start() 方法利用這些屬性創建一個新的 Process 實例。start() 方法可以從同一實例重復調用,以利用相同的或相關的屬性創建新的子進程。 (我在《深入研究java.lang.Runtime類》中講過,進程也可以由Runtime.exec()啟動。)
每個進程生成器(即ProcessBuilder對象)管理這些進程屬性:
? ? ?命令?是一個字符串列表,它表示要調用的外部程序文件及其參數(如果有)。在此,表示有效的操作系統命令的字符串列表是依賴于系統的。例如,每一個總體變量,通常都要成為此列表中的元素,但有一些操作系統,希望程序能自己標記命令行字符串——在這種系 ?統中,Java 實現可能需要命令確切地包含這兩個元素。?
? ? 環境?是從變量 到值 的依賴于系統的映射。初始值是當前進程環境的一個副本(請參閱 System.getenv())。?
? ? 工作目錄?默認值是當前進程的當前工作目錄,通常根據系統屬性 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()來間接創建其實例。
?
注意:????? 修改進程構建器的屬性將影響后續由該對象的 start() 方法啟動的進程,但從不會影響以前啟動的進程或 Java 自身的進程。
????? ProcessBuilder類不是同步的。如果多個線程同時訪問一個 ProcessBuilder,而其中至少一個線程從結構上修改了其中一個屬性,它必須保持外部同步。 啟動一個使用默認工作目錄和環境的新進程:? Process p = new ProcessBuilder("myCommand", "myArg").start();? 下面是一個利用修改過的工作目錄和環境啟動進程的例子:? ProcessBuilder pb = new ProcessBuilder("myCommand", "myArg1", "myArg2");
?Map<String, String> env = pb.environment();
?env.put("VAR1", "myValue");
?env.remove("OTHERVAR");
?env.put("VAR2", env.get("VAR1") + "suffix");
?pb.directory("myDir");
?Process p = pb.start();
?要利用一組明確的環境變量啟動進程,在添加環境變量之前,首先調用 Map.clear()。? 二、API預覽
????構造方法摘要?
??? ProcessBuilder(List<String> command)?
????? 利用指定的操作系統程序和參數構造一個進程生成器。?
??? ProcessBuilder(String... command)?
????? 利用指定的操作系統程序和參數構造一個進程生成器。 方法摘要?
??? command()?
????? 返回此進程生成器的操作系統程序和參數。?
??? command(List<String> command)?
????? 設置此進程生成器的操作系統程序和參數。?
??? command(String... command)?
????? 設置此進程生成器的操作系統程序和參數。?
??? directory()?
????? 返回此進程生成器的工作目錄。?
??? directory(File directory)?
????? 設置此進程生成器的工作目錄。?
??? environment()?
????? 返回此進程生成器環境的字符串映射視圖。?
??? redirectErrorStream()?
????? 通知進程生成器是否合并標準錯誤和標準輸出。?
??? redirectErrorStream(boolean redirectErrorStream)?
????? 設置此進程生成器的 redirectErrorStream 屬性。?
? ? ?start()? 使用此進程生成器的屬性啟動一個新進程實例Process ,可以操作Process對象:詳解?
三、常見應用
????? 若要使用ProcessBuilder創建一個進程,只需要創建ProcessBuilder的一個實例,指定該進程的名稱和所需參數。要執行此程序,調用該實例上的start()即可。 1,下面上一個執行Windows記事本的例子。注意它將要編輯的文件名指定為一個參數。 class PBDemo { public static void main(String args[]) { try { ProcessBuilder proc = new ProcessBuilder("notepad.exe", "testfile"); proc.start(); } catch (Exception e) { System.out.println("Error executing notepad."); } } } 2,ProcessBuilder的應用簡單來說就是,先生成一個ProcessBuilder對象:
ProcessBuilder提供了兩個構造函數,ProcessBuilder(List<String>?command) 和?ProcessBuilder(String...?command
我這里使用的是第二個,因為是需要在Linux系統上執行shell腳本,所以,我的構造函數為:
ProcessBuilder pb = new ProcessBuilder("sh"); (ps:你也可以對應的使用“Python”或者在windows上使用“cmd”)
執行的命令的應用程序已經選好了,那我們的輸入和輸出呢,怎么設置,這是我們關心的地方。
推薦使用redirectInput(File?file) ,讓我們用這個方法來獲取輸入,同理使用redirectOutput(File?file)
來處理輸出,如果有錯誤的話,還需要使用redirectError(File?file)
由于涉及到的參數都是File類型的,所以,你需要先生成這幾個文件,然后再使用它們
執行完后,可以去outfile里面查看執行結果,你也可以把結果讀出后返回,將file.sh和outfile這兩個臨時文件刪除。
?
package com.pmqin.quartz.domian;import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.text.SimpleDateFormat; import java.util.Date;public class ProcessBuildertest {public static void main(String[] args) {String file = "!/bin/sh\r\n" // linux 的換行是\n,注意換+ "a=\'Hello world\'\r\n" + "echo $a\r\n";String result = Process("sh", file,true);System.out.println(result);} catch (Exception e) {System.out.println("Error executing notepad.");}}public static String Process(String cmd, String commandlist,boolean isSavefile) throws IOException, InterruptedException {File input = new File("./file.sh");createNewFile(input);PrintWriter print = new PrintWriter(input);print.append(commandlist);print.flush();print.close();String result = "SUCCESS";try {File output = null;if (isSavefile) {output = new File("./outfile");createNewFile(output);}ProcessBuilder pb = new ProcessBuilder(cmd);pb.redirectErrorStream(true);//如果將值設置為 true,標準錯誤將與標準輸出合并,在此情況下,合并的數據可從 Process.getInputStream() 返回的流讀取 pb.redirectInput(input);if (isSavefile) {pb.redirectOutput(output); //表示把輸出重定向到指定的文件里面 } Process process = pb.start();//異步的// 獲取執行的結果if (!isSavefile) {InputStream in = process.getInputStream();//同步System.out.println("等待執行完成");String streamtxt=getInputStream(in); System.out.println(streamtxt);}if (process.waitFor() != 0) {//InputStream error = process.getErrorStream();result="Err";}process.destroy();} catch (IOException e) {result = "FAIL";e.printStackTrace();}return result;}/*** inputStream 文件流 轉成字符串* @param inputStream 文件流* @return* @throws IOException*/public static String getInputStream(InputStream inputStream) throws IOException {StringBuilder stringBuilder = new StringBuilder();BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "gb2312"));String line = null;while ((line = bufferedReader.readLine()) != null) {stringBuilder.append(System.getProperty("line.separator"));stringBuilder.append(line);}return stringBuilder.toString();}/*** 判斷文件是否存在,不存在就創建* @param file* @throws IOException */public static void createNewFile(File file) throws IOException { if (!file.exists()) {file.createNewFile();}}?
轉載于:https://www.cnblogs.com/mistor/p/6129682.html
總結
以上是生活随笔為你收集整理的浅析Java.lang.ProcessBuilder类的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 状态压缩 HDU 1565
- 下一篇: 预备作业02-20162314王译潇 黑
