1. 程式人生 > >ProcessBuilder中如何為命令列傳參

ProcessBuilder中如何為命令列傳參

專案中有個需求是備份資料庫,備份資料庫很自然的想到使用mysqldump進行轉儲,那麼問題的關鍵就變成了如何在java中呼叫mysqldump命令,一搜才知道通過開啟一個本地的程序,來執行該命令即可。
Process的產生有兩種方式:Runtime.getRuntime.exec(cmd),另一種是通過ProcessBuilder builder,builder.start()。
Process是一個抽象類,只能通過這兩種方式來獲取一個Process物件。在獲取到Process之後,可以通過getInputStream()獲取子程序的輸出流,注意,子程序沒有console,因此,它的stdout\stdin\stderr都被重定向到父程序,也就是java程序中。

Runtime

起初採用Runtime來進行操作,方法如下:
String cmd = “mysqldump.exe -h ” + host + ” -u ” + username + ” -p” + password + ” ” + dbName;
Process process = Runtime.getRuntime().exec(cmd);

這個方法可以正常work,但是我查詢JDK,發現官方推薦是使用ProcessBuilder,原因是
Because some native platforms only provide limited buffer size for standard input and output streams, failure to promptly write the input stream or read the output stream of the subprocess may cause the subprocess to block, or even deadlock.

其實我並沒有太懂。。。。

不過有一點,當執行命令過程中發生錯誤時怎麼辦?當然可以使用getErrorStream()來獲取錯誤資訊。但是,但是,我懶,,如果能重定向到inputstream就可以了。於是ProcessBuilder來了。

ProcessBuilder

ProcessBulder是一個final類,可以直接例項化,通過為ProcessBuilder傳入命令引數,然後start()就可以建立一個滿足引數的Process,注意只有在start時才會建立一個新的程序。JDK上說大多數的錯誤都是在start時產生的。。。
果然,,,
起初,我是這樣建立ProcessBuilder builder = new ProcessBuilder(cmd);//cmd為上面的命令列。
然後報錯了,說是找不到檔案,,,,
在網上找解決方案:

http://blog.csdn.net/iaiti/article/details/45268991,上面說要為“指令中有空格的需要用不同的字串分開。”
然後我寫成這個樣子

new ProcessBuilder("mysqldump.exe"," ","-h"," ",host," ","-u"," ",root," ","-p",password"," ",dbName);

然後它告訴我說找不到資料庫名,然後我就把順序來回倒,倒來倒去,最後琢磨過來,如果說我是程式設計者,我希望把option和值分開嗎?就像”-h”,” “,host一樣?這樣感覺好傻,我希望做的應該是將這幾個東西放在一起,然後對於多個引數的情況,分為多個字串即可。即

new ProcessBuilder("mysqldump.exe",dbName,"-h"+host,"-u"+username,"-p"+password);

結果果然,再執行就沒有錯誤了。然後通過builder.redirectErrorStream()重定向到錯誤流就達到我們之前的目的了。

當然,這裡直接在命令列裡傳密碼是不大安全的,但是,在Enter password:裡面傳引數怎麼做???請知情者不吝賜教。

waitfor

這裡還有一個坑,就是waitfor(),起初我以為waitfor是指阻塞在這樣,然後等命令列讀取完成之後就恢復執行,結果不是,,,waitfor()等待的是子程序的退出,,,之前程式裡面加入了waitfor()直接死在這裡了。當然了,加入一個超時時間是可以的。其實在通過process獲取inputstream的時候,系統就已經阻塞了。所以,並不懂waitfor()的作用是什麼。。

destroy

destroy是另外一個坑,當java中的方法執行完退出時,並不會使得子程序退出,子程序何時會退出完全取決於作業系統,那在這裡,我認為子程序命令執行完畢之後,要顯式將process.destroy()掉,防止消耗資源,特別是伺服器系統而言。