Java ProcessBuilder 类
最后修改时间:2025 年 4 月 13 日
java.lang.ProcessBuilder
类用于创建操作系统进程。 与 Runtime.exec
方法相比,它提供了更多控制,用于使用特定的环境、工作目录和 I/O 重定向来启动进程。
ProcessBuilder 允许您在启动进程之前配置进程属性。 您可以设置命令、参数、环境变量、工作目录以及重定向标准输入/输出/错误流。
ProcessBuilder 基础知识
ProcessBuilder 类用于创建操作系统进程。 每个 ProcessBuilder 实例管理一组进程属性。 start
方法使用这些属性创建一个新的 Process 实例。
public final class ProcessBuilder { public ProcessBuilder(List<String> command) {...} public ProcessBuilder(String... command) {...} public ProcessBuilder command(List<String> command) {...} public ProcessBuilder command(String... command) {...} public List<String> command() {...} public ProcessBuilder directory(File directory) {...} public File directory() {...} public ProcessBuilder redirectInput(ProcessBuilder.Redirect source) {...} public ProcessBuilder redirectOutput(ProcessBuilder.Redirect destination) {...} public ProcessBuilder redirectError(ProcessBuilder.Redirect destination) {...} public ProcessBuilder.Redirect redirectInput() {...} public ProcessBuilder.Redirect redirectOutput() {...} public ProcessBuilder.Redirect redirectError() {...} public ProcessBuilder inheritIO() {...} public Map<String,String> environment() {...} public Process start() throws IOException {...} }
上面的代码展示了 ProcessBuilder 类提供的主要方法。 这些方法允许在启动进程之前对其进行配置。
基本进程执行
此示例演示了使用 ProcessBuilder 执行系统命令的最简单方法。 我们将执行 "echo" 命令来打印一条消息。
package com.zetcode; import java.io.IOException; public class BasicProcess { public static void main(String[] args) { try { ProcessBuilder pb = new ProcessBuilder("echo", "Hello, ProcessBuilder!"); Process process = pb.start(); int exitCode = process.waitFor(); System.out.println("Process exited with code: " + exitCode); } catch (IOException | InterruptedException e) { e.printStackTrace(); } } }
在本例中,我们使用 "echo" 命令及其参数创建一个 ProcessBuilder。 start
方法启动进程,而 waitFor
等待其完成。 请注意,这个简单的例子并没有捕获进程的输出。
读取进程输出
此示例展示了如何捕获和读取进程的输出。 我们将执行 "ls" 命令来列出目录内容并打印输出。
package com.zetcode; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; public class ReadOutput { public static void main(String[] args) { try { ProcessBuilder pb = new ProcessBuilder("ls", "-l"); Process process = pb.start(); // Read the output from the process BufferedReader reader = new BufferedReader( new InputStreamReader(process.getInputStream())); String line; while ((line = reader.readLine()) != null) { System.out.println(line); } int exitCode = process.waitFor(); System.out.println("\nProcess exited with code: " + exitCode); } catch (IOException | InterruptedException e) { e.printStackTrace(); } } }
在这里,我们使用 getInputStream
来获取进程的标准输出流。 我们将其包装在 BufferedReader 中以逐行读取输出。 当您需要在 Java 中处理命令输出时,此模式很常见。
设置工作目录
此示例演示了如何为进程设置工作目录。 我们将在特定目录中执行 "ls" 命令。
package com.zetcode; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; public class WorkingDirectory { public static void main(String[] args) { try { ProcessBuilder pb = new ProcessBuilder("ls"); pb.directory(new File("/tmp")); // Set working directory System.out.println("Working directory: " + pb.directory()); Process process = pb.start(); BufferedReader reader = new BufferedReader( new InputStreamReader(process.getInputStream())); String line; while ((line = reader.readLine()) != null) { System.out.println(line); } int exitCode = process.waitFor(); System.out.println("\nProcess exited with code: " + exitCode); } catch (IOException | InterruptedException e) { e.printStackTrace(); } } }
directory
方法设置进程的工作目录。 在本例中,我们列出了 "/tmp" 目录的内容。 工作目录会影响执行命令使用的相对路径。
环境变量
此示例演示了如何修改进程的环境变量。 我们将添加一个自定义变量并打印环境。
package com.zetcode; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.Map; public class EnvironmentVars { public static void main(String[] args) { try { ProcessBuilder pb = new ProcessBuilder("printenv"); // Get and modify the environment Map<String, String> env = pb.environment(); env.put("CUSTOM_VAR", "Hello from Java!"); System.out.println("Environment variables:"); env.forEach((k, v) -> System.out.println(k + "=" + v)); Process process = pb.start(); BufferedReader reader = new BufferedReader( new InputStreamReader(process.getInputStream())); String line; while ((line = reader.readLine()) != null) { System.out.println(line); } int exitCode = process.waitFor(); System.out.println("\nProcess exited with code: " + exitCode); } catch (IOException | InterruptedException e) { e.printStackTrace(); } } }
environment
方法返回一个可修改的环境变量映射。 我们添加了自定义变量,该变量将可用于子进程。 "printenv" 命令显示所有环境变量。
将输出重定向到文件
此示例演示了如何将进程输出重定向到文件,而不是在 Java 中读取它。 我们将把 "ls" 的输出保存到一个文件中。
package com.zetcode; import java.io.File; import java.io.IOException; public class RedirectOutput { public static void main(String[] args) { try { ProcessBuilder pb = new ProcessBuilder("ls", "-l"); // Redirect output to a file pb.redirectOutput(new File("output.txt")); Process process = pb.start(); int exitCode = process.waitFor(); System.out.println("Process completed. Output saved to output.txt"); System.out.println("Exit code: " + exitCode); } catch (IOException | InterruptedException e) { e.printStackTrace(); } } }
redirectOutput
方法将进程的标准输出定向到文件。 当您想保存命令输出而不使用 Java 处理它时,这很有用。 如果文件不存在,它将被创建;如果文件存在,它将被覆盖。
处理错误流
此示例展示了如何处理标准输出和错误流。 我们将执行一个产生错误输出的命令并捕获这两个流。
package com.zetcode; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; public class ErrorHandling { public static void main(String[] args) { try { ProcessBuilder pb = new ProcessBuilder("ls", "nonexistent_file"); // Merge error stream with output stream pb.redirectErrorStream(true); Process process = pb.start(); BufferedReader reader = new BufferedReader( new InputStreamReader(process.getInputStream())); String line; while ((line = reader.readLine()) != null) { System.out.println(line); } int exitCode = process.waitFor(); System.out.println("\nProcess exited with code: " + exitCode); } catch (IOException | InterruptedException e) { e.printStackTrace(); } } }
通过设置 redirectErrorStream(true)
,我们将错误流与标准输出流合并。 这简化了通过单个 InputStream 读取这两个流的过程。 对于错误情况,退出代码将非零。
运行多个命令
此示例演示了如何按顺序执行多个命令。 我们将运行两个命令并检查它们的状态码。
package com.zetcode; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; public class MultipleCommands { public static void main(String[] args) { List<String> commands = new ArrayList<>(); commands.add("date"); commands.add("uname -a"); for (String cmd : commands) { try { System.out.println("Executing: " + cmd); ProcessBuilder pb = new ProcessBuilder(cmd.split(" ")); pb.redirectErrorStream(true); Process process = pb.start(); BufferedReader reader = new BufferedReader( new InputStreamReader(process.getInputStream())); String line; while ((line = reader.readLine()) != null) { System.out.println(line); } int exitCode = process.waitFor(); System.out.println("Exit code: " + exitCode + "\n"); } catch (IOException | InterruptedException e) { e.printStackTrace(); } } } }
此示例展示了如何按顺序执行多个命令。 我们将每个命令字符串拆分为 ProcessBuilder 的各个部分。 每个命令的输出和退出代码都会显示。 这种模式对于运行几个系统命令非常有用。
来源
在本文中,我们通过实际示例介绍了 Java ProcessBuilder 类。 ProcessBuilder 提供了用于从 Java 应用程序执行和管理系统进程的强大功能。
作者
列出所有Java教程。