相关文章推荐
果断的火腿肠  ·  浙江工商大学2024年工商管理硕士(MBA) ...·  1 年前    · 
痴情的帽子  ·  首日票部分已售罄 ...·  1 年前    · 
俊逸的炒饭  ·  芋圆呀呀-天竺少女 – 几次元 - 百度·  1 年前    · 
贪玩的野马  ·  【发现音乐】帕瓦罗蒂为什么总能得到女孩的芳心 ...·  1 年前    · 
仗义的登山鞋  ·  奋力书写“造福人民的幸福河”时代答卷 - 求是网·  1 年前    · 
Code  ›  Java学习笔记 调用外部程序开发者社区
社区功能 bytes
https://cloud.tencent.com/developer/article/1016039
帅呆的佛珠
2 年前
作者头像
乐百川
0 篇文章

Java学习笔记 调用外部程序

前往专栏
腾讯云
开发者社区
文档 意见反馈 控制台
首页
学习
活动
专区
工具
TVP
文章/答案/技术大牛
发布
首页
学习
活动
专区
工具
TVP
返回腾讯云官网
社区首页 > 专栏 > 乐百川的学习频道 > Java学习笔记 调用外部程序

Java学习笔记 调用外部程序

作者头像
乐百川
发布 于 2018-01-08 18:23:48
1.1K 0
发布 于 2018-01-08 18:23:48
举报

在Java中可以调用外部程序,这需要通过Process等类来实现。

创建进程

先来介绍一下Process的创建,我们需要使用 ProcessBuilder 类。如果需要命令行参数的话,则传入多个参数。比方说下面我就创建了一个查看Java版本号的 ProcessBuilder 。

ProcessBuilder pb = new ProcessBuilder("java","-version");

ProcessBuilder 还有一些成员方法,可以重定向输入输出流到文件、设置命令行参数等等。如果需要详细的使用方法可以参考 官方文档 。

有了 ProcessBuilder 仅仅是第一步,我们还没有实际执行程序。为了执行程序,我们需要调用它的 start() 方法,这会启动进程并返回一个 Process 对象。如果需要 Process 的详细信息,请参考 Java官方文档 。

Process process = pb.start();

这样的话,命令行对应的进程就会开始执行。我们可以调用 Process 的 exitValue() 方法获取进程是否成功返回(一般返回0为正常退出,记得C语言最后的 return 0 吗)。如果需要获取进程的输出,可以调用 getInputStream() 获取程序的输入流。需要注意进程的输入输出和我们Java程序的输入输出方向正好是相反的,所以如果我们想要向进程中传递参数,就需要调用它的 getOutputStream 获取输出流。

byte[] bytes = new byte[process.getInputStream().available()];
process.getInputStream().read(bytes);
System.out.println(new String(bytes));

进程的阻塞

如果你实际执行上面的代码的话,很可能抛出 IllegalThreadStateException 。因为在我们获取程序输出的时候,很有可能当前进程并没有结束。那么获取结果就是不合法的操作。因此,为了安全的等待进程结束,我们需要调用 waitFor() 方法,阻塞当前线程,直到进程退出为止。

所以最后的代码类似这样。在进程启动之后,我们需要阻塞,直到它结束。然后获取返回值和输出结果。

ProcessBuilder pb = new ProcessBuilder("java","-version");
Process process = pb.start();
process.waitFor();
System.out.println(process.exitValue());
byte[] bytes = new byte[process.getInputStream().available()];
process.getInputStream().read(bytes);
System.out.println(new String(bytes));

输出流的处理

上面的代码应该没有问题,而且实际执行的时候,返回值为0,。这说明我们确实成功地执行了 java -version 命令。但是,如果你实际执行的话,会发现程序也仅仅输出了返回值。那么我们期望的实际输出去哪儿了?

如果研究一下 ProcessBuilder 的文档的话,会发现有这么一个方法 redirectErrorStream(boolean) ,该方法的作用是将子进程的错误流重定向到标准输出流上。这样我们使用 Process.getInputStream() 就可以获取到所有输出了。

所以最后的代码如下。

ProcessBuilder pb = new ProcessBuilder("java","-version");
pb.redirectErrorStream(true);
Process process = pb.start();
process.waitFor();
System.out.println(process.exitValue());
byte[] bytes = new byte[process.getInputStream().available()];
process.getInputStream().read(bytes);
System.out.println(new String(bytes));

结果会显示当前安装的Java版本号信息。

0
java version "1.8.0_121"
Java(TM) SE Runtime Environment (build 1.8.0_121-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.121-b13, mixed mode)

其他例子

通过一番研究,我们得到了Java调用外部进程的模板例子。只需要简单替换一下命令行参数即可启动不同的程序。

记事本

调用 notepad 就可以启动记事本了。由于我们调用了 process.waitFor() ,所以当记事本窗口关闭前,Java程序也不会关闭。同理, calc 可以启动计算器, explorer 可以启动资源管理器。

ProcessBuilder pb = new ProcessBuilder("notepad");
pb.redirectErrorStream(true);
Process process = pb.start();
process.waitFor();
System.out.println(process.exitValue());
byte[] bytes = new byte[process.getInputStream().available()];
process.getInputStream().read(bytes);
System.out.println(new String(bytes));

查看当前Windows版本

这个也很简单,只需要在命令提示符窗口中输入 ver 即可。但是我们不能直接将进程名写为 ver 。因为实际上没有这个程序,这只是命令提示符的功能而已。所以代码要修改一下,我们调用的进程实际上是 cmd ,参数是 ver 。

另外默认编码是UTF-8,而在中文操作系统下编码是GBK。所以会出现乱码。所以输出流的代码也需要修改,我们将它包装到 BufferedReader 中, BufferedReader 有一个接受字符集参数的构造方法。而且 BufferedReader 在Java 8中还新增了一个 lines() 方法,返回所有输入行的 stream ,我们可以利用Java 8的流类库和lambda表达式方便的处理。

ProcessBuilder pb = new ProcessBuilder("cmd", "/c", "ver");
pb.redirectErrorStream(true);
Process process = pb.start();
process.waitFor();
 
推荐文章
果断的火腿肠  ·  浙江工商大学2024年工商管理硕士(MBA)招生简章
1 年前
痴情的帽子  ·  首日票部分已售罄 夕发朝至去香港的高铁票你买到了吗?
1 年前
俊逸的炒饭  ·  芋圆呀呀-天竺少女 – 几次元 - 百度
1 年前
贪玩的野马  ·  【发现音乐】帕瓦罗蒂为什么总能得到女孩的芳心?歌剧中男高音总是主角?
1 年前
仗义的登山鞋  ·  奋力书写“造福人民的幸福河”时代答卷 - 求是网
1 年前
今天看啥   ·   Py中国   ·   codingpro   ·   小百科   ·   link之家   ·   卧龙AI搜索
删除内容请联系邮箱 2879853325@qq.com
Code - 代码工具平台
© 2024 ~ 沪ICP备11025650号