使用进程运行shell命令时的java块

时间:2017-07-28 03:00:45

标签: java processbuilder youtube-dl

我有一个Java项目,可帮助您使用youtube-dl查找YouTube播放列表中的所有视频信息。这是Main.java

import java.io.*;


public class Main {

public static void main(String[] args) throws Exception {
    String command1 = "/usr/local/bin/youtube-dl --flat-playlist --dump-single-json https://www.youtube.com/playlist?list=PLFcOH1YaRqUo1yEjY5ly09RFbIpUePF7G";
    String command2 = "/usr/local/bin/youtube-dl --flat-playlist --dump-single-json https://www.youtube.com/playlist?list=PLC6A0625DCA9AAE2D";
    System.out.println(executeCommand(command1));

}

private static String executeCommand(String command) throws IOException, InterruptedException {
    int exitCode = 0;
    String result = "";
    Process process;
    ProcessBuilder builder = new ProcessBuilder(command.replaceAll("[ ]+", " ").split(" "));
    builder.directory(new File("/tmp/test"));
    process = builder.start();
    exitCode = process.waitFor();
    return getStringFromInputStream(process.getInputStream());
}
private static String getStringFromInputStream(InputStream is) {

    BufferedReader br = null;
    StringBuilder sb = new StringBuilder();

    String line;
    try {

        br = new BufferedReader(new InputStreamReader(is));
        while ((line = br.readLine()) != null) {
            sb.append(line);
        }

    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (br != null) {
            try {
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    return sb.toString();
}
}

除了Youbute播放列表参数外,command1command2相同。 command2中的播放列表包含409个视频,在command1中有200个视频。我可以在终端中成功获得两个命令的结果。仅command2需要更多时间,但只需几秒钟。但是当我运行Main.java(javac Main.java; java Main)时,对于command1,它会成功打印结果,但对于command2,它会挂起几分钟而没有任何结果。以下是此过程的jstack

"main" #1 prio=5 os_prio=0 tid=0x00007f828c009800 nid=0xce7 in Object.wait() [0x00007f8293cf7000]
java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x0000000771df9fe0> (a java.lang.UNIXProcess)
    at java.lang.Object.wait(Object.java:502)
    at java.lang.UNIXProcess.waitFor(UNIXProcess.java:396)
    - locked <0x0000000771df9fe0> (a java.lang.UNIXProcess)
    at Main.executeCommand(Main.java:18)
    at Main.main(Main.java:8)

它挂在exitCode = process.waitFor();。我不知道。谁能帮我?非常感谢。

1 个答案:

答案 0 :(得分:2)

如评论中所述,默认情况下,子流程的输出将发送到可以使用Process.getInputStream()读取的管道。如果子进程生成大量输出且Java程序没有使用它,则管道缓冲区将填满,子进程将在写入时阻塞。

最简单的解决方案是在ProcessBuilder上调用.inheritIO()。这会将输出发送到控制台,而不是在内存中缓冲它(输入和错误流相同)。