Java 执行命令

在进行开发的时候, 我们有时候需要通过命令来执行别的程序,并获取返回结果。

    public static void main(String[] args) throws Exception{

        String cmd = "ls";

        Process ps = Runtime.getRuntime().exec(new String[]{"sh", "-c", cmd});
        
        String stdout = new String(readAll(ps.getInputStream()));
        String stderr = new String(readAll(ps.getErrorStream()));

        ps.waitFor();

        System.out.println("stdout is :" + stdout);
        System.out.println("stderr is :" + stderr);
        System.out.println("exit code is :" + exitCode);
    }


    static byte[] readAll(InputStream is) throws Exception{
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        byte[] bytes = new byte[1024];
        int n;
        while (( n = is.read(bytes)) != -1) {
            os.write(bytes, 0, n);
        }
        return os.toByteArray();
    }

但是在实际使用过程中有时会出现问题, 调用命令启动的子进程会卡住,永远得不到返回。

原因是: 子进程和父进程之间建立管道连接, 子进程的错误输出和标准输出会向两个不同的管道进行写入,而管道的缓冲区有大小限制,当子进程执行过程中错误输出过多,并且没有标准输出时。 java进程的读标准输出时会block住,而子进程把管道缓冲区打满,子进程也会block住,这样就会产生死锁。

解决方案: 启动两个线程来读取输出

    public static void main(String[] args) throws Exception{

        String cmd = "ls";

        Process ps = Runtime.getRuntime().exec(new String[]{"sh", "-c", cmd});

        Future stdoutFuture =
                Executors.newSingleThreadExecutor().submit(() -> new String(readAll(ps.getInputStream())));
        Future stderrFuture =
                Executors.newSingleThreadExecutor().submit(() -> new String(readAll(ps.getErrorStream())));

        int exitCode = ps.waitFor();

        System.out.println("stdout is :" + stdoutFuture.get());
        System.out.println("stderr is :" + stderrFuture.get());
        System.out.println("exit code is :" + exitCode);
    }


    static byte[] readAll(InputStream is) throws Exception{
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        byte[] bytes = new byte[1024];
        int n;
        while (( n = is.read(bytes)) != -1) {
            os.write(bytes, 0, n);
        }
        return os.toByteArray();
    }

你可能感兴趣的:(Java 执行命令)