Java Process 类
最后修改时间:2025 年 4 月 13 日
java.lang.Process 类提供了与系统进程交互的方法。它允许 Java 程序启动、控制和与原生操作系统进程进行通信。这对于系统级编程至关重要。
Process 对象由 Runtime.exec 或 ProcessBuilder.start 方法创建。它们代表在 Java 虚拟机外部运行的本机进程。该类提供了获取输入/输出流、等待完成和检查退出状态的方法。
Process 类方法
Process 类提供了多种用于进程管理的方法。这些方法包括用于 I/O 流访问、进程终止和状态检查的方法。该类是抽象类,平台特定的实现由 JVM 提供。
public abstract class Process {
public abstract OutputStream getOutputStream();
public abstract InputStream getInputStream();
public abstract InputStream getErrorStream();
public abstract int waitFor() throws InterruptedException;
public abstract int exitValue();
public abstract void destroy();
public Process destroyForcibly();
public boolean isAlive();
public boolean waitFor(long timeout, TimeUnit unit);
}
上面的代码显示了 Process 类提供的主要方法。这些方法允许控制外部进程并通过标准流进行通信。现代 Java 版本添加了更多方法,以实现更好的进程控制。
基本进程执行
此示例演示如何执行简单的系统命令并等待其完成。我们使用 Runtime.getRuntime().exec 启动进程。waitFor 方法会阻塞,直到进程完成。
package com.zetcode;
import java.io.IOException;
public class Main {
public static void main(String[] args) {
try {
// Execute a system command
Process process = Runtime.getRuntime().exec("notepad.exe");
// Wait for the process to complete
int exitCode = process.waitFor();
System.out.println("Process exited with code: " + exitCode);
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
}
在本例中,我们启动 Windows 记事本并等待它关闭。waitFor 方法返回进程的退出代码。请注意,这是一个阻塞调用 - Java 程序将等待,直到记事本关闭。
读取进程输出
此示例演示如何读取进程的输出。我们执行一个产生输出的命令,并通过进程的输入流读取它。这对于捕获命令结果至关重要。
package com.zetcode;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class Main {
public static void main(String[] args) {
try {
// Execute a command that produces output
Process process = Runtime.getRuntime().exec("cmd /c dir");
// Get the input stream of the process
InputStream inputStream = process.getInputStream();
BufferedReader reader = new BufferedReader(
new InputStreamReader(inputStream));
// Read the output line by line
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
// Close resources
reader.close();
process.waitFor();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
}
在这里,我们执行 Windows dir 命令并读取其输出。进程的标准输出可通过 getInputStream 访问。我们将它包装在 BufferedReader 中,以便高效地逐行读取。完成后始终关闭流,以防止资源泄漏。
处理进程错误
此示例演示如何从进程读取错误输出。错误输出可通过 getErrorStream 获取的单独流获得。正确的错误处理对于健壮的进程管理至关重要。
package com.zetcode;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class Main {
public static void main(String[] args) {
try {
// Execute a command that might produce errors
Process process = Runtime.getRuntime().exec("cmd /c dir nonexistent");
// Read standard output
readStream(process.getInputStream(), "OUTPUT");
// Read error output
readStream(process.getErrorStream(), "ERROR");
process.waitFor();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
private static void readStream(InputStream inputStream, String type)
throws IOException {
BufferedReader reader = new BufferedReader(
new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(type + ": " + line);
}
reader.close();
}
}
在此示例中,我们尝试列出不存在的目录,这会生成错误输出。我们分别读取标准输出和错误流。错误流通常包含命令失败时的诊断消息。应始终读取两个流,以防止进程挂起。
写入进程输入
此示例演示如何将数据写入进程的输入流。某些程序接受通过其标准输入接收的输入。我们通过与 Python 解释器通信来演示这一点。
package com.zetcode;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
public class Main {
public static void main(String[] args) {
try {
// Start Python interpreter
Process process = Runtime.getRuntime().exec("python");
// Get the output stream to write to the process
OutputStream outputStream = process.getOutputStream();
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(outputStream));
// Write Python commands to the process
writer.write("print(2 + 3)\n");
writer.write("exit()\n");
writer.flush();
// Read the output
readStream(process.getInputStream(), "PYTHON OUTPUT");
process.waitFor();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
private static void readStream(java.io.InputStream inputStream, String type)
throws IOException {
java.io.BufferedReader reader = new java.io.BufferedReader(
new java.io.InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(type + ": " + line);
}
reader.close();
}
}
在这里,我们启动 Python 解释器并通过其标准输入向其发送命令。我们通过 getOutputStream 获取输出流,并将 Python 代码写入其中。写入后,我们必须刷新流以确保发送数据。然后从输入流读取 Python 输出。
ProcessBuilder 示例
此示例演示了用于进程创建的现代 ProcessBuilder 方法。ProcessBuilder 比 Runtime.exec() 提供对进程创建的更多控制。它允许设置环境变量和工作目录。
package com.zetcode;
import java.io.IOException;
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
try {
// Create ProcessBuilder with command and arguments
ProcessBuilder pb = new ProcessBuilder("cmd", "/c", "echo", "Hello, ProcessBuilder!");
// Redirect error stream to standard output
pb.redirectErrorStream(true);
// Start the process
Process process = pb.start();
// Read the combined output
readStream(process.getInputStream(), "OUTPUT");
int exitCode = process.waitFor();
System.out.println("Exit code: " + exitCode);
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
private static void readStream(java.io.InputStream inputStream, String type)
throws IOException {
java.io.BufferedReader reader = new java.io.BufferedReader(
new java.io.InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(type + ": " + line);
}
reader.close();
}
}
此示例使用 ProcessBuilder 执行带有参数的命令。我们设置 redirectErrorStream(true) 以将错误输出与标准输出合并。ProcessBuilder 比 Runtime.exec() 更受欢迎,因为它具有灵活性,并且可以更好地处理命令参数。它可以自动处理参数引用和拆分。
检查进程状态
此示例演示如何检查进程是否仍在运行并获取其退出值。isAlive 方法检查进程状态,而 exitValue 获取进程终止时的退出代码。
package com.zetcode;
import java.io.IOException;
public class Main {
public static void main(String[] args) {
try {
// Start a long-running process
Process process = Runtime.getRuntime().exec("ping -n 5 localhost");
// Check process status periodically
for (int i = 0; i < 10; i++) {
if (process.isAlive()) {
System.out.println("Process is still running...");
} else {
System.out.println("Process exited with code: " +
process.exitValue());
break;
}
Thread.sleep(1000);
}
// If still running after 10 seconds, destroy it
if (process.isAlive()) {
System.out.println("Terminating process...");
process.destroy();
}
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
}
在这里,我们启动一个 ping 命令,该命令运行约 5 秒钟。我们使用 isAlive 定期检查其状态。如果进程在 10 秒后仍在运行,我们使用 destroy 终止它。请注意,如果在正在运行的进程上调用 exitValue,则会引发异常。
销毁进程
此示例演示了终止进程的不同方法。destroy 方法请求正常终止,而 destroyForcibly 尝试在需要时强制终止。
package com.zetcode;
import java.io.IOException;
public class Main {
public static void main(String[] args) {
try {
// Start a process that will run indefinitely
Process process = Runtime.getRuntime().exec("notepad.exe");
System.out.println("Process started. Waiting 5 seconds...");
Thread.sleep(5000);
// Try to destroy the process gracefully
System.out.println("Attempting to destroy process...");
process.destroy();
// Wait a bit to see if it terminates
Thread.sleep(1000);
if (process.isAlive()) {
System.out.println("Process still alive. Forcing termination...");
Process forced = process.destroyForcibly();
forced.waitFor();
System.out.println("Forced termination complete.");
} else {
System.out.println("Process terminated gracefully.");
}
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
}
在本例中,我们启动记事本并尝试以编程方式关闭它。首先,我们尝试使用 destroy 进行正常终止。如果进程在一秒钟后仍然存活,我们使用 destroyForcibly。destroyForcibly 方法返回一个 Process 对象,该对象可用于等待终止。这提供了对进程终止的更多控制。
来源
在本文中,我们通过实际示例介绍了 Java Process 类。进程管理对于系统集成和外部命令执行至关重要。Process 类为 Java 中的这些操作提供了基础。
作者
列出所有Java教程。