中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何解決使用ProcessBuilder的遇到的問題

發布時間:2021-06-09 09:50:41 來源:億速云 閱讀:460 作者:小新 欄目:開發技術

這篇文章主要介紹如何解決使用ProcessBuilder的遇到的問題,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!

使用ProcessBuilder踩到的坑

最近使用ProcessBuilder執行命令,命令內容正確,但始終報錯命令實行失敗,是因為不熟悉ProcessBuilder用法踩到了坑,記錄一下。

先看一下我模擬出來的錯誤

如何解決使用ProcessBuilder的遇到的問題

要執行的命令:cp -rf /tmp/monkey/a.log /home/monkey/ 簡單的cp命令拷貝一個文件,卻報錯說文件不存在。確認過文件確實存在該目錄下。

如何解決使用ProcessBuilder的遇到的問題

查看jdk 中,我使用的ProcessBuilder(***) 源碼實現如下,并不是一個單獨的字符串String形式,而是支持多個字符串,同時還有List集合方式。

如何解決使用ProcessBuilder的遇到的問題

如何解決使用ProcessBuilder的遇到的問題

于是想到會不會是ProcessBuilderbuilder不支持包含空格的命令。

動手寫了下面的代碼進行測試

public class ProcessBuilderDemo {
    /**
     * 測試processBuilder執行cp命令
     * cp /tmp/monkey/a.log /home/monkey/
     * 源路徑    args[1]: /tmp/monkey/a.log
     * 目標路徑  args[2]: /home/monkey/
     * 方法名    args[3]
     * @param args
     */
    public static void main(String[] args) {
        String src = args[0];
        String tag = args[1];
        String method = args.length == 3 ? args[2] : null;
        if (method != null && method.equals("string")) {
            cmdIsString(src, tag);
        } else {
            cmdIsListOrArray(src, tag);
        }
    }
    /**
     * 執行命令,命令用拼接成一個字符串形式(會包含空格)
     * @param src 源路徑
     * @param tag 目標路徑
     */
    private static void cmdIsString(String src, String tag) {
        String cmd = "cp";
        cmd = cmd + " -rf" + " " + src + " " + tag;
        System.out.println("command is: " + cmd);
        ProcessBuilder builder = new ProcessBuilder(cmd);
        try {
            Process process = builder.start();
            process.waitFor();
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println(e.toString());
        }
    }
    /**
     * 執行命令,命令各個部分拼接成一個數組或者ArrayList集合
     * 該方法采用數組實現
     * @param src 源路徑
     * @param tag 目標路徑
     */
    private static void cmdIsListOrArray(String src, String tag) {
        String cmd = "cp";
        // 命令的各個部分組成一個字符串數組,用該數組創建ProcessBuilder對象
        String[] cmds = new String[] {cmd, "-rf", src, tag};
        ProcessBuilder builder = new ProcessBuilder(cmds);
        try {
            Process process = builder.start();
            process.waitFor();
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println(e.toString());
        }
    }
}

果然如我所猜想的一樣:包含有空格的命令執行會報錯。

以下是cmdIsListOrArray方法,將命令的內容組成字符串的形式執行的結果,而文章第一張圖則是直接當做一條完整命令的執行結果。

如何解決使用ProcessBuilder的遇到的問題

至于為什么不能好有空格暫時未做深入了解,有帶佬可以釋疑嗎?難道一條完整的命令當做一個字符串它不香嘛?

while(true) {
    伸手黨;
}

使用ProcessBuilder執行本地程序的注意事項

錯誤代碼

public static void main(String[] args) throws IOException, InterruptedException {
        ProcessBuilder processBuilder = new ProcessBuilder("java","-version");
        Process process = processBuilder.start();
        InputStream inputStream = process.getInputStream();
        xxx(inputStream);
    }
  
    private static void xxx(InputStream inputStream) throws IOException {
        BufferedReader input = new BufferedReader(new InputStreamReader(inputStream));
        String ss=null;
        while ((ss=input.readLine())!=null){
            System.out.println(ss);
        }
    }

使用ProcessBuilder類帶參執行命令容易出現的兩個坑

1、執行后沒有任何反映

原因為通過ProcessBuilder運行的參數還沒有執行完畢程序就退出了。

通過if(process.isAlive()){process.waitFor();}可以規避此問題,但是需要注意waitFor時程序時阻塞的,如果是持續運行的web項目可以通過開啟子線程來執行ProcessBuilder

2、執行后沒有任何輸出

最惡心的地方,除了getInputStream外還有一個getErrorStream也可以獲取數據,而且一般執行的程序數據都會輸出在getErrorStream中,所以getInputStream無法獲取到數據

處理后的代碼

public static void main(String[] args) throws IOException, InterruptedException {
        ProcessBuilder processBuilder = new ProcessBuilder("java","-version");
        processBuilder.redirectErrorStream(true);//將錯誤流中的數據合并到輸入流
        Process process = processBuilder.start();
        if(process.isAlive()){
            process.waitFor();
        }
//        InputStream errorStream = process.getErrorStream();
        InputStream inputStream = process.getInputStream();
//        xxx(errorStream);
        xxx(inputStream);
    }
 
    private static void xxx(InputStream inputStream) throws IOException {
        BufferedReader input = new BufferedReader(new InputStreamReader(inputStream));
        String ss=null;
        while ((ss=input.readLine())!=null){
            System.out.println(ss);
        }
    }

后續發現新的問題,當某個軟件會持續向流中寫數據,這時流中數據沒有被讀取完畢(流中存在數據【測試發現流中存在數據并不是一定會阻塞】),會導致waitFor一直陷入阻塞

上述問題處理后的代碼(正確使用ProcessBuilder的代碼)

 public static void main(String[] args) throws IOException, InterruptedException {
        ProcessBuilder processBuilder = new ProcessBuilder("java","-version");
        processBuilder.redirectErrorStream(true);
        Process process = processBuilder.start();
//        通過標準輸入流來拿到正常和錯誤的信息
        InputStream inputStream = process.getInputStream();
        BufferedReader input = new BufferedReader(new InputStreamReader(inputStream));
        String ss=null;
        while ((ss=input.readLine())!=null){
            System.out.println(ss);
        }
        process.waitFor();
    }

復現錯誤:

1、某個軟件持續向流中寫數據時,如果流中數據未被讀取完畢waitFor一直陷入等待

public static void main(String[] args) throws IOException, InterruptedException {
        ProcessBuilder processBuilder = new ProcessBuilder();
        List<String> meta = new ArrayList<String>();
        meta.add("ffmpeg");
        meta.add("-i");
        meta.add("C:/Users/Lenovo/Desktop/20200801134820261.mp3");
        meta.add("-af");
        meta.add("silencedetect=n=-1dB:d=0.5");
        meta.add("-f");
        meta.add("null");
        meta.add("-");
        processBuilder.command(meta);
        processBuilder.redirectErrorStream(true);
        Process process = processBuilder.start();
        InputStream inputStream = process.getInputStream();
//        BufferedReader input = new BufferedReader(new InputStreamReader(inputStream));
//        String ss=null;
//        while ((ss=input.readLine())!=null){
//            System.out.println(ss);
//        }
        process.waitFor();
        System.out.println("一直阻塞無法執行到這一步");
    }

2、通過下面代碼證明上面的觀點:當將流中數據讀取完畢后waitFor不會阻塞,可執行下一步

public static void main(String[] args) throws IOException, InterruptedException {
    ProcessBuilder processBuilder = new ProcessBuilder();
    List<String> meta = new ArrayList<String>();
    meta.add("ffmpeg");
    meta.add("-i");
    meta.add("C:/Users/Lenovo/Desktop/20200801134820261.mp3");
    meta.add("-af");
    meta.add("silencedetect=n=-1dB:d=0.5");
    meta.add("-f");
    meta.add("null");
    meta.add("-");
    processBuilder.command(meta);
    processBuilder.redirectErrorStream(true);
    Process process = processBuilder.start();
    InputStream inputStream = process.getInputStream();
    BufferedReader input = new BufferedReader(new InputStreamReader(inputStream));
    String ss=null;
    while ((ss=input.readLine())!=null){
        System.out.println(ss);
    }
    process.waitFor();
    System.out.println("正常輸出");
}

3、與上面觀點產生矛盾的代碼:下面代碼中的流中仍然存在數據,但是waitFor并沒有陷入阻塞,推測原因可能是由于ipconfig與ffmpeg不同,不存在 持續向流中寫數據情況,因此waitFor可以正常結束阻塞

public static void main(String[] args) throws IOException, InterruptedException {
        ProcessBuilder processBuilder = new ProcessBuilder();
        List<String> meta = new ArrayList<String>();
        meta.add("ipconfig");
        processBuilder.command(meta);
        processBuilder.redirectErrorStream(true);
        Process process = processBuilder.start();
        InputStream inputStream = process.getInputStream();
//        BufferedReader input = new BufferedReader(new InputStreamReader(inputStream));
//        String ss=null;
//        while ((ss=input.readLine())!=null){
//            System.out.println(ss);
//        }
        process.waitFor();
        System.out.println("正常輸出");
    }

以上是“如何解決使用ProcessBuilder的遇到的問題”這篇文章的所有內容,感謝各位的閱讀!希望分享的內容對大家有幫助,更多相關知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

昭平县| 准格尔旗| 左权县| 商城县| 买车| 任丘市| 清原| 江川县| 息烽县| 泾阳县| 博乐市| 伊川县| 宜兰县| 武穴市| 湖州市| 靖边县| 嘉兴市| 衡阳县| 江孜县| 霍州市| 青岛市| 高雄市| 山东省| 曲麻莱县| 饶平县| 都匀市| 华阴市| 文安县| 永清县| 哈密市| 广宁县| 剑阁县| 涟源市| 邯郸市| 武乡县| 三亚市| 遂平县| 太仆寺旗| 财经| 邻水| 东乌珠穆沁旗|