重要参考文章(强力推荐,使用Process类调用外部程序必看的文章):
http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html?page=4
这篇文章讲的大概是Runtime.getRuntime()调用外部程序可能潜在的问题并给出如何解决的方法,逐步推进,是一篇不错的文章。
我的使用场景是在java中调用/bin/sh执行一些命令,并获取命令的执行结果。
Process p=Runtime.getRuntime().exec(String[] cmdArr);
因为我想要执行一些文本处理,涉及到多个程序,不可避免的需要管道操作,所以选择了上面的形式让/bin/sh代理执行管道功能。
不妨把p看成一个Java创建的与执行命令的外部进程(由/bin/sh创建)进行交互的进程:
|----------------| |-------------
p.getInputStream()-------| Java创建的 |<-----Normal Output---| /bin/sh创建的 |
| 交互进程P | | 外部进程 |
p.getErrorStream()------ | |<------Error Output---| |
|----------------| |-------------|
从上图可以看到p的inputStream其实就是外部进程的标准输出,p的errorStream对应外部进程的标准错误。
引文建议使用两个同时处理进程P的inputStream和errorStream,这是必要的。
我第一次使用时,并没有同时处理,而是先处理错误输出,如果错误输出不为空,就直接结束。
否则再处理标准输出。
------这种做法会出现阻塞的现象---当进程P的输出很大时---不知道是怎么回事,据引文的说法,似乎是
不采用同时读时,你无法判断哪个流的数据最先开始,所以可能出现无法读取,一直阻塞的现象。
然而,当你采用同时读取的方法时,也有一些要注意的,而这在引文中并没有提到:
以下是引文给出的做法:
Listing 4.7 GoodWinRedirect.java
import java.util.*;
import java.io.*;
class StreamGobbler extends Thread
{
InputStream is;
String type;
OutputStream os;
StreamGobbler(InputStream is, String type)
{
this(is, type, null);
}
StreamGobbler(InputStream is, String type, OutputStream redirect)
{
this.is = is;
this.type = type;
this.os = redirect;
}
public void run()
{
try
{
PrintWriter pw = null;
if (os != null)
pw = new PrintWriter(os);
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line=null;
while ( (line = br.readLine()) != null)
{
if (pw != null)
pw.println(line);
System.out.println(type + ">" + line);
}
if (pw != null)
pw.flush();
} catch (IOException ioe)
{
ioe.printStackTrace();
}
}
}
Listing 4.8 TestExec.java
import java.util.*;
import java.io.*;
// class StreamGobbler omitted for brevity
public class TestExec
{
public static void main(String args[])
{
if (args.length < 1)
{
System.out.println("USAGE: java TestExec \"cmd\"");
System.exit(1);
}
try
{
String cmd = args[0];
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec(cmd);
// any error message?
StreamGobbler errorGobbler = new
StreamGobbler(proc.getErrorStream(), "ERR");
// any output?
StreamGobbler outputGobbler = new
StreamGobbler(proc.getInputStream(), "OUT");
// kick them off
errorGobbler.start();
outputGobbler.start();
// any error???
int exitVal = proc.waitFor();
System.out.println("ExitValue: " + exitVal);
//这里有些问题
} catch (Throwable t)
{
t.printStackTrace();
}
}
}
使用这种方法,有时候会出现异常----提示流已经被关闭了,
BufferedReader br = new BufferedReader(isr);
String line=null;
//流被关闭,无法读取,这里会抛出异常
while ( (line = br.readLine()) != null)
{
if (pw != null)
pw.println(line);
System.out.println(type + ">" + line);
}
为什么呢?
我们可以想到,因为进程P相当于给我们创建了两个管道,但是对于管道的读取,作读取的线程是不知道流什么时候关闭的,当进程P关闭管道后,线程仍然在读取,所以会抛出异常。
合理的方法是主线程等待两个读取线程的结束。
即是在
// kick them off
errorGobbler.start();
outputGobbler.start();
// any error???
int exitVal = proc.waitFor();
System.out.println("ExitValue: " + exitVal);
//加入
errorGobbler.join();
outputGobbler.join();
int exitVal = proc.waitFor();//这句只是等待进程P的结束,而此时两个线程仍然在读取的,如果就此跳过,可能会抛出异常
分享到:
相关推荐
本篇文章主要介绍了JAVA如何调用Shell脚本,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
###Java中执行adb shell命令本项目中,adb shell命令执行的实现方法主要参考网文()。文章中,把执行代码集成在ShellUtils工具类中,执行结果返回CommandResult这个类。ShellUtils与CommandResult这两个类的说明可...
主要给大家介绍了关于利用Python+Java调用Shell脚本时的死锁陷阱的相关资料,文章通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。
1个目标文件,JNDI的使用例子,有源代码,可以下载参考,JNDI的使用,初始化Context,它是连接JNDI树的起始点,查找你要的对象,打印找到的对象,关闭Context…… ftp文件传输 2个目标文件,FTP的目标是:(1)提高...
Java从网络取得文件 1个目标文件 简单 Java从压缩包中提取文件 1个目标文件 简单 Java存储与读取对象 1个目标文件 如题 Java调色板面板源代码 1个目标文件 摘要:Java源码,窗体界面,调色板 使用Java语言编写的一款...
基于hadoop的Hive数据仓库JavaAPI简单调用的实例,关于Hive的简介在此不赘述。hive提供了三种用户接口:CLI,JDBC/ODBC和 WebUI CLI,即Shell命令行 JDBC/ODBC 是 Hive 的Java,与使用传统数据库JDBC的方式类似 Web...
这些文件详细展示了如何使用Java、HTML、JavaScript、CSS和Shell等技术构建一个面向学生和心理教师的心理健康信息管理系统,该系统支持学生在线进行心理测试、咨询心理教师、发帖讨论等功能,以及心理教师进行测试...
这里只是讲了路线图,关于路线中的各个阶段,学到什么程度,如何学习等,可以参考后面的JAVA自学之路 七:《路线图明细》。 首先要学JavaSE,这是无庸置疑的。 与此同时,是的,与此同时,和JavaSE的学习同步,...
这篇文章主要介绍了编写shell脚本,使用iconv批量改变文件编码的脚本代码,需要的朋友可以参考下。 用法示例: cd ~/workspace/XXXProject ~/iconv_shell.sh ./ *java 好了,直接上代码~~ #!/bin/bash if [ $# != 2...
java写dll接口源码(介绍)Java 本机接口编程,通过示例 注意:我现在正在考虑向本教程添加内容。 如果您有建议或新增内容,请不要犹豫。 目录 前言 注意:我在 2017 年初写了这篇文章,因为需要将图像序列化任务从 ...
SWT(Standard Widget Toolkit)是IBM推出的“基于java”的图形界面开发库,我之所以说它是“基于java”的意思是程序员编写代码的时候是使用java语言,事实上SWT的底层实现是C语言完成的。但是这些对程序员是透明的。 ...
无论他们在哪里,都可以写文章,代码,笔记或与朋友见面。极限编程会议,辅导和创意写作的理想选择。 强大的编辑 细颗粒还原 可以按照您的方式执行撤消操作,而不必将太多的编辑分组在一起。 块编辑 同时在多行...
有一个shell命令“输入”,可以帮助您将文本输入发送到Android系统。 usage: input [text|keyevent] input text input keyevent 但是您不能使用此命令发送unicode字符,因为它并非旨在以这种方式使用它。 参考...
后端可以使用 java -jar hexoblogadmin.war 的方式直接运行, 或者部署到tomcat容器中 可以使用supervisor 或 systemd 托管springboot应用,避免退出shell后进程终止 ### TODO - 头像上传 - 系统参数设置 √ - ...
本书可作为Unix用户学习的教程和参考书。 目 录 译者序 前言 第一部分 电子邮件 第1章 电子邮件概述 1 1.1 用户网络地址 1 1.1.1 Internet域寻址方式 2 1.1.2 UUCP路径寻址方式 3 1.2 发送和接收邮件 3 1.3 收到...
3. 如果涉及到引用文章,请附上参考引用链接。 4. 当前进度 | 章节号 | 标题 | 进度 | 负责人&参与人 | | ------ | ------------------ | ------ | -------------------------------------- | | 第一章 | 投资与...
在对内存块进行了 free 调用之后,我们需要做的是诸如将它们标记为未被使用的等事情,并且,在调用 malloc 时,我们要能够定位未被使用的内存块。因此, malloc 返回的每块内存的起始处首先要有这个结构: 清单 3...
* CGI 程序可以使用 Perl、shell、C++、Java 等语言编写。 * CGI 程序的特点包括:内容的生成与显示进行别离、强调可重用的组件等。 知识点4:JSP * JSP 的特点包括:内容的生成与显示进行别离、强调可重用的组件...
Ivan Idris以编写简洁可测试的程序代码以及撰写有趣的技术文章为乐,同时也是Packt出版社NumPy Beginner's Guide-Second Edition、NumPy Cookbook和Learning NumPy Array等书籍的作者。读者可以访问ivanidris.net...
主要功能为:基本信息、命令执行、虚拟终端、文件管理、Socks 代理、反弹 shell、数据库管理、自定义代码等,功能非常强大。 加密原理 --------- 我们以 PHP 版本为例,"冰蝎" 在服务端支持 open_ssl 时,使⽤ AES...