ProcessBuilder启动外部进程

wen java案例 3

ProcessBuilder 启动外部进程

ProcessBuilder 是 Java 中用于创建操作系统进程的类,相比旧版的 Runtime.exec(),它提供了更灵活和强大的控制能力。

ProcessBuilder启动外部进程

基本用法

创建并启动简单进程

import java.io.*;
public class ProcessBuilderExample {
    public static void main(String[] args) throws IOException {
        // 创建 ProcessBuilder 实例
        ProcessBuilder pb = new ProcessBuilder("ls", "-la");
        // 启动进程
        Process process = pb.start();
        // 读取输出
        BufferedReader reader = new BufferedReader(
            new InputStreamReader(process.getInputStream()));
        String line;
        while ((line = reader.readLine()) != null) {
            System.out.println(line);
        }
    }
}

核心功能

设置工作目录

ProcessBuilder pb = new ProcessBuilder("cmd", "/c", "dir");
// 设置工作目录
pb.directory(new File("C:/Users/YourName"));

环境变量管理

ProcessBuilder pb = new ProcessBuilder("printenv");
Map<String, String> env = pb.environment();
// 添加/修改环境变量
env.put("MY_VAR", "custom_value");
env.put("PATH", env.get("PATH") + ":/custom/path");
// 清除所有环境变量
env.clear();

重定向输入输出

ProcessBuilder pb = new ProcessBuilder("grep", "error");
// 从文件读取输入
pb.redirectInput(new File("input.log"));
// 输出到文件
pb.redirectOutput(new File("output.txt"));
// 错误输出合并到标准输出
pb.redirectErrorStream(true);
// 或者单独重定向错误输出
pb.redirectError(new File("error.log"));

完整示例

执行复杂命令并处理输出

import java.io.*;
import java.util.concurrent.TimeUnit;
public class ProcessBuilderDemo {
    public static void main(String[] args) {
        try {
            // 创建命令列表(Windows 示例)
            ProcessBuilder pb = new ProcessBuilder(
                "cmd.exe", 
                "/c", 
                "ping -n 3 8.8.8.8"
            );
            // 配置进程
            pb.directory(new File("C:/temp"));
            pb.redirectErrorStream(true);
            // 启动进程
            Process process = pb.start();
            // 读取输出
            try (BufferedReader reader = new BufferedReader(
                    new InputStreamReader(process.getInputStream()))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    System.out.println("OUTPUT: " + line);
                }
            }
            // 等待进程完成(带超时)
            boolean finished = process.waitFor(30, TimeUnit.SECONDS);
            if (finished) {
                int exitCode = process.exitValue();
                System.out.println("进程退出码: " + exitCode);
            } else {
                System.out.println("进程超时,强制终止");
                process.destroyForcibly();
            }
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }
}

高级用法

使用管道(Pipe)

import java.util.List;
public class PipeExample {
    public static void main(String[] args) throws IOException {
        // 创建两个进程
        ProcessBuilder pb1 = new ProcessBuilder("ls", "-la");
        ProcessBuilder pb2 = new ProcessBuilder("grep", "java");
        // 启动第一个进程
        Process process1 = pb1.start();
        // 将第一个进程的输出作为第二个进程的输入
        Process process2 = pb2.start();
        // 连接管道
        try (InputStream is = process1.getInputStream();
             OutputStream os = process2.getOutputStream()) {
            byte[] buffer = new byte[1024];
            int length;
            while ((length = is.read(buffer)) != -1) {
                os.write(buffer, 0, length);
            }
        }
        // 读取最终结果
        BufferedReader reader = new BufferedReader(
            new InputStreamReader(process2.getInputStream()));
        String line;
        while ((line = reader.readLine()) != null) {
            System.out.println(line);
        }
    }
}

常见平台命令示例

public class PlatformSpecific {
    // Linux/Mac 命令
    public static void unixCommands() throws IOException {
        // 列出目录
        new ProcessBuilder("ls", "-la", "/tmp").start();
        // 执行脚本
        new ProcessBuilder("bash", "-c", "echo 'Hello'").start();
        // 查看进程
        new ProcessBuilder("ps", "-ef").start();
    }
    // Windows 命令
    public static void windowsCommands() throws IOException {
        // 列出目录
        new ProcessBuilder("cmd", "/c", "dir").start();
        // 查看进程
        new ProcessBuilder("tasklist").start();
        // IP 配置
        new ProcessBuilder("ipconfig", "/all").start();
    }
}

错误处理最佳实践

public class RobustProcessBuilder {
    public static void executeCommand(List<String> command) {
        Process process = null;
        try {
            ProcessBuilder pb = new ProcessBuilder(command);
            pb.redirectErrorStream(true);
            process = pb.start();
            // 启动读取线程防止缓冲阻塞
            Thread outputReader = new Thread(() -> {
                try (BufferedReader reader = new BufferedReader(
                        new InputStreamReader(process.getInputStream()))) {
                    String line;
                    while ((line = reader.readLine()) != null) {
                        System.out.println(line);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
            outputReader.start();
            // 等待完成
            if (!process.waitFor(10, TimeUnit.SECONDS)) {
                process.destroyForcibly();
                throw new RuntimeException("进程超时");
            }
            int exitCode = process.exitValue();
            if (exitCode != 0) {
                throw new RuntimeException("进程返回非零退出码: " + exitCode);
            }
        } catch (IOException | InterruptedException e) {
            throw new RuntimeException("执行命令失败: " + command, e);
        } finally {
            if (process != null) {
                process.destroy();
            }
        }
    }
}

关键注意事项

  1. 线程安全: Process 不是线程安全的,要考虑并发访问
  2. 资源释放: 始终关闭 InputStream/OutputStream
  3. 阻塞问题: 大输出可能导致进程阻塞,使用独立线程读取
  4. 跨平台: 注意命令在不同操作系统上的差异
  5. 安全: 避免命令注入,使用参数列表而非字符串拼接

ProcessBuilder 为 Java 提供了强大且可靠的外部进程管理能力,合理使用可以很好地扩展应用的功能边界。

抱歉,评论功能暂时关闭!