原文:http://zetcode.com/java/processbuilder/
Java ProcessBuilder教程显示了如何使用ProcessBuilder创建操作系统进程。
ProcessBuilder
ProcessBuilder用于创建操作系统进程。 其start()方法创建具有以下属性的新Process实例:
- 命令
- 环境
- 工作目录
- 输入来源
- 标准输出和标准错误输出的目标
redirectErrorStream
ProcessBuilder运行程序
用command()执行程序。 使用waitFor(),我们可以等待过程完成。
ExecuteProgram.java
package com.zetcode;import java.io.IOException;public class ExecuteProgram {public static void main(String[] args) throws IOException, InterruptedException {var processBuilder = new ProcessBuilder();processBuilder.command("notepad.exe");var process = processBuilder.start();var ret = process.waitFor();System.out.printf("Program exited with code: %d", ret);}}
该程序执行 Windows 记事本应用。 它返回其退出代码。
ProcessBuilder命令输出
以下示例执行命令并显示其输出。
ProcessBuilderEx.java
package com.zetcode;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;public class ProcessBuilderEx {public static void main(String[] args) throws IOException {var processBuilder = new ProcessBuilder();processBuilder.command("cal", "2019", "-m 2");var process = processBuilder.start();try (var reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {String line;while ((line = reader.readLine()) != null) {System.out.println(line);}}}}
该示例运行 Linux cal命令。
processBuilder.command("cal", "2019", "-m 2");
command()执行cal程序。 其他参数是程序的选项。 为了在 Windows 机器上运行命令,我们可以使用以下命令:processBuilder.command("cmd.exe", "/c", "ping -n 3 google.com")。
var process = processBuilder.start();
start()启动了该过程。
try (var reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
使用getInputStream()方法,我们从流程的标准输出中获取输入流。
February 2019Su Mo Tu We Th Fr Sa1 23 4 5 6 7 8 910 11 12 13 14 15 1617 18 19 20 21 22 2324 25 26 27 28
这是输出。
ProcessBuilder重定向输出
使用redirectOutput(),我们可以重定向流程构建器的标准输出目的地。
RedirectOutputEx.java
package com.zetcode;import java.io.BufferedReader;import java.io.File;import java.io.IOException;import java.io.InputStreamReader;public class RedirectOutputEx {public static void main(String[] args) throws IOException {var homeDir = System.getProperty("user.home");var processBuilder = new ProcessBuilder();processBuilder.command("cmd.exe", "/c", "date /t");var fileName = new File(String.format("%s/Documents/tmp/output.txt", homeDir));processBuilder.redirectOutput(fileName);var process = processBuilder.start();try (var reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {String line;while ((line = reader.readLine()) != null) {System.out.println(line);}}}}
该程序将构建器的输出重定向到文件。 它运行 Windows date命令。
processBuilder.redirectOutput(fileName);
我们将流程构建器的标准输出重定向到文件。
try (var reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {String line;while ((line = reader.readLine()) != null) {System.out.println(line);}}
现在输出到文件。
$ echo %cd%C:\Users\Jano\Documents\tmp$ more output.txtThu 02/14/2019
当前日期已写入output.txt文件。
ProcessBuilder重定向输入和输出
下一个示例同时重定向输入和输出。
src/resources/input.txt
skybluesteelmorningcoffeeearthforest
这是input.txt文件的内容。
ProcessBuilderRedirectIOEx.java
package com.zetcode;import java.io.File;import java.io.IOException;public class ProcessBuilderRedirectIOEx {public static void main(String[] args) throws IOException {var processBuilder = new ProcessBuilder();processBuilder.command("cat").redirectInput(new File("src/resources", "input.txt")).redirectOutput(new File("src/resources/", "output.txt")).start();}}
在程序中,我们将输入从input.txt文件重定向到cat命令,并将命令的输出重定向到output.txt文件。
ProcessBuilder继承 IO
inheritIO()将子流程标准 I/O 的源和目的地设置为与当前 Java 流程相同。
ProcessBuilderInheritIOEx.java
package com.zetcode;import java.io.IOException;public class ProcessBuilderInheritIOEx {public static void main(String[] args) throws IOException, InterruptedException {var processBuilder = new ProcessBuilder();processBuilder.command("cmd.exe", "/c", "dir");var process = processBuilder.inheritIO().start();int exitCode = process.waitFor();System.out.printf("Program ended with exitCode %d", exitCode);}}
通过继承已执行命令的 IO,我们可以跳过读取步骤。 程序输出项目目录的内容和显示退出代码的消息。
02/14/2019 04:55 PM <DIR> .02/14/2019 04:55 PM <DIR> ..02/19/2019 01:11 PM <DIR> .idea02/14/2019 04:55 PM <DIR> out02/14/2019 04:52 PM 433 ProcessBuilderInheritIOEx.iml02/14/2019 04:53 PM <DIR> src1 File(s) 433 bytes5 Dir(s) 157,350,264,832 bytes freeProgram ended with exitCode 0
我们同时获得执行的命令和自己的 Java 程序的输出。
ProcessBuilder环境
environment()方法返回流程构建器环境的字符串映射视图。
ProcessBuilderEnvEx.java
package com.zetcode;public class ProcessBuilderEnvEx {public static void main(String[] args) {var pb = new ProcessBuilder();var env = pb.environment();env.forEach((s, s2) -> {System.out.printf("%s %s %n", s, s2);});System.out.printf("%s %n", env.get("PATH"));}}
该程序显示所有环境变量。
configsetroot C:\WINDOWS\ConfigSetRootUSERDOMAIN_ROAMINGPROFILE LAPTOP-OBKOFV9JLOCALAPPDATA C:\Users\Jano\AppData\LocalPROCESSOR_LEVEL 6USERDOMAIN LAPTOP-OBKOFV9JLOGONSERVER \\LAPTOP-OBKOFV9JJAVA_HOME C:\Users\Jano\AppData\Local\Programs\Java\openjdk-11\SESSIONNAME Console...
这是 Windows 上的示例输出。
在下一个程序中,我们定义一个自定义环境变量。
ProcessBuilderEnvEx2.java
package com.zetcode;import java.io.IOException;public class ProcessBuilderEnvEx2 {public static void main(String[] args) throws IOException {var pb = new ProcessBuilder();var env = pb.environment();env.put("mode", "development");pb.command("cmd.exe", "/c", "echo", "%mode%");pb.inheritIO().start();}}
该程序定义一个mode变量并在 Windows 上输出。
pb.command("cmd.exe", "/c", "echo", "%mode%");
%mode%是 Windows 的环境变量语法; 在 Linux 上,我们使用$mode。
ProcessBuilder目录
directory()方法设置流程构建器的工作目录。
ProcessBuilderDirectoryEx.java
package com.zetcode;import java.io.BufferedReader;import java.io.File;import java.io.IOException;import java.io.InputStreamReader;public class ProcessBuilderDirectoryEx {public static void main(String[] args) throws IOException {var homeDir = System.getProperty("user.home");var pb = new ProcessBuilder();pb.command("cmd.exe", "/c", "dir");pb.directory(new File(homeDir));var process = pb.start();try (var reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {String line;while ((line = reader.readLine()) != null) {System.out.println(line);}}}}
该示例将主目录设置为流程生成器的当前目录。 我们显示主目录的内容。
var homeDir = System.getProperty("user.home");
我们得到用户的主目录。
pb.command("cmd.exe", "/c", "dir");
我们定义了一个在 Windows 上执行dir程序的命令。
pb.directory(new File(homeDir));
我们设置流程构建器的目录。
Volume in drive C is WindowsVolume Serial Number is 4415-13BBDirectory of C:\Users\Jano02/14/2019 11:48 AM <DIR> .02/14/2019 11:48 AM <DIR> ..10/13/2018 08:38 AM <DIR> .android01/31/2019 10:58 PM 281 .bash_history12/17/2018 03:02 PM <DIR> .config...
这是一个示例输出。
ProcessBuilder非阻塞操作
在下面的示例中,我们创建一个异步过程。
ProcessBuilderNonBlockingEx.java
package com.zetcode;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.util.List;import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.Executors;import java.util.concurrent.Future;import java.util.concurrent.TimeUnit;import java.util.concurrent.TimeoutException;import java.util.stream.Collectors;public class ProcessBuilderNonBlockingEx {public static void main(String[] args) throws InterruptedException,ExecutionException, TimeoutException, IOException {var executor = Executors.newSingleThreadExecutor();var processBuilder = new ProcessBuilder();processBuilder.command("cmd.exe", "/c", "ping -n 3 google.com");try {var process = processBuilder.start();System.out.println("processing ping command ...");var task = new ProcessTask(process.getInputStream());Future<List<String>> future = executor.submit(task);// non-blocking, doing other tasksSystem.out.println("doing task1 ...");System.out.println("doing task2 ...");var results = future.get(5, TimeUnit.SECONDS);for (String res : results) {System.out.println(res);}} finally {executor.shutdown();}}private static class ProcessTask implements Callable<List<String>> {private InputStream inputStream;public ProcessTask(InputStream inputStream) {this.inputStream = inputStream;}@Overridepublic List<String> call() {return new BufferedReader(new InputStreamReader(inputStream)).lines().collect(Collectors.toList());}}}
该程序创建一个在控制台上运行ping命令的进程。 它在Executors.newSingleThreadExecutor()方法的帮助下在单独的线程中执行。
processing ping command ...doing task1 ...doing task2 ...Pinging google.com [2a00:1450:4001:825::200e] with 32 bytes of data:Reply from 2a00:1450:4001:825::200e: time=108msReply from 2a00:1450:4001:825::200e: time=111msReply from 2a00:1450:4001:825::200e: time=112msPing statistics for 2a00:1450:4001:825::200e:Packets: Sent = 3, Received = 3, Lost = 0 (0% loss),Approximate round trip times in milli-seconds:Minimum = 108ms, Maximum = 112ms, Average = 110ms
这是输出。
ProcessBuilder管道操作
管道是一种用于将信息从一个程序进程传递到另一个程序进程的技术。
ProcessBuilderPipeEx.java
package com.zetcode;import java.io.File;import java.io.IOException;public class ProcessBuilderPipeEx {public static void main(String[] args) throws IOException {var homeDir = System.getProperty("user.home");var processBuilder = new ProcessBuilder();processBuilder.command("cmd.exe", "/c", "dir | grep [dD]o");processBuilder.directory(new File(homeDir));processBuilder.inheritIO().start();}}
该示例通过管道(|)将信息从dir命令发送到grep命令。
Volume in drive C is Windows11/14/2018 06:57 PM <DIR> .dotnet02/18/2019 10:54 PM <DIR> Documents02/17/2019 01:11 AM <DIR> Downloads
这是输出。
在本教程中,我们使用 Java 的ProcessBuilder执行 OS 进程。 您可能也对相关教程感兴趣: Java Files.walk教程和 Java 教程。
