- 浏览: 124692 次
- 性别:
- 来自: 山东
最新评论
在上一篇(Java动态编译(一))中我们提到了动态编译的三种方法,在这篇文章中讲解一些扩展的知识。
ProcessBuilder.start() 和 Runtime.exec 方法创建一个本机进程,并返回 Process 子类的一个实例,该实例可用来控制进程并获得相关信息。
子进程没有自己的终端或控制台。它的所有标准io(即 stdin、stdout 和 stderr)操作都将通过三个流 (getOutputStream()、getInputStream() 和 getErrorStream()) 重定向到父进程。
waitFor() 导致当前线程等待,如有必要,一直要等到由该Process对象表示的进程已经终止。但是如果我们在调用此方法时,如果不注意的话,很容易出现主线程阻塞,Process也挂起的情况。在调用waitFor() 的时候,Process需要向主线程汇报运行状况,所以要注意清空缓存区,即InputStream和ErrorStream,在网上,很多只提到处理InputStream,忽略了ErrorStream。
举例1.
上面的程序并没有按照我们预想的那样列出g盘下的目录,而是挂起了,为什么会出现这种情况呢?java文档上说,创建进程的方法可能无法针对某些本机平台上的特定进程很好地工作,比如,本机窗口进程,守护进程,Microsoft Windows 上的 Win16/DOS 进程,或者 shell 脚本。创建的子进程没有自己的终端或控制台。它的所有标准io(即 stdin、stdout 和 stderr)操作都将通过三个流 (getOutputStream()、getInputStream() 和 getErrorStream()) 重定向到父进程。父进程使用这些流来提供到子进程的输入和获得从子进程的输出。因为有些本机平台仅针对标准输入和输出流提供有限的缓冲区大小,如果读写子进程的输出流或输入流迅速出现失败,则可能导致子进程阻塞,甚至产生死锁。
当进程启动后,就会打开标准输出流和错误输出流准备输出,当进程结束时,就会关闭他们。在举例1中,由于标准输出流有数据需要输出,但是我们却没有读取其中的数据,标准输出流就会一直等待数据被读取,程序挂起。
举例2.处理标准输出流
当我们处理了标准输出后,则程序可以正常运行了。但是,如果我们的命令是错误的,那么情况又会如何呢?即这里将dir修改成dira,然后执行。程序仍然可以正常运行,只不过结束的时候的exitVal不再是0。
为什么会出现这种情况呢?这里就是当我们执行程序的时候,先打开的是标准输出流,然后等待我们从中读取数据,而我们对需要读取的数据做了读取处理。那么当接下来打开错误输出流的时候,尽管没有被读取,但是却不再阻塞,程序异常终止。
但是,如果命令是正确的(即dira已经改回dir)再将process.getInputStream()修改成process.getErrorStream()呢?这次程序又一起挂起了。这是由于标准输出流是先打开并需要输出而,但是却并没有被读取;读取的是错误输出流,那么此时标准输出流的数据没有被读取导致程序不会结束。
为了解决这个问题,可以根据输出的实际先后,先读取标准输出流,然后读取错误输出流。
但是,很多时候不能很明确的知道输出的先后,特别是要操作标准输入的时候,情况就会更为复杂。这时候可以采用线程来对标准输出、错误输出和标准输入进行分别处理,根据他们之间在业务逻辑上的关系决定读取那个流或者写入数据。
针对标准输出流和错误输出流所造成的问题,还可以使用ProcessBuilder的redirectErrorStream()方法将他们合二为一,这时候只要读取标准输出的数据就可以了。
举例3.使用多线程
举例4.是用ProcessBuilder.redirectErrorStream()
通知进程生成器是否合并标准错误和标准输出。
如果此属性为 true,则任何由通过此对象的 start() 方法启动的后续子进程生成的错误输出都将与标准输出合并,因此两者均可使用 Process.getInputStream() 方法读取。这使得关联错误消息和相应的输出变得更容易。初始值为 false。
public abstract class Process extends Object
ProcessBuilder.start() 和 Runtime.exec 方法创建一个本机进程,并返回 Process 子类的一个实例,该实例可用来控制进程并获得相关信息。
子进程没有自己的终端或控制台。它的所有标准io(即 stdin、stdout 和 stderr)操作都将通过三个流 (getOutputStream()、getInputStream() 和 getErrorStream()) 重定向到父进程。
waitFor() 导致当前线程等待,如有必要,一直要等到由该Process对象表示的进程已经终止。但是如果我们在调用此方法时,如果不注意的话,很容易出现主线程阻塞,Process也挂起的情况。在调用waitFor() 的时候,Process需要向主线程汇报运行状况,所以要注意清空缓存区,即InputStream和ErrorStream,在网上,很多只提到处理InputStream,忽略了ErrorStream。
举例1.
public class RuntimeExecDemo { public static void main(String[] args) throws InterruptedException { Runtime runtime = Runtime.getRuntime(); Process process = null; try { process = runtime.exec("cmd /c dir", null, new File("g:/")); } catch (IOException e) { e.printStackTrace(); } int exitVal = process.waitFor(); System.out.println("Process exitValue: " + exitVal); } }
上面的程序并没有按照我们预想的那样列出g盘下的目录,而是挂起了,为什么会出现这种情况呢?java文档上说,创建进程的方法可能无法针对某些本机平台上的特定进程很好地工作,比如,本机窗口进程,守护进程,Microsoft Windows 上的 Win16/DOS 进程,或者 shell 脚本。创建的子进程没有自己的终端或控制台。它的所有标准io(即 stdin、stdout 和 stderr)操作都将通过三个流 (getOutputStream()、getInputStream() 和 getErrorStream()) 重定向到父进程。父进程使用这些流来提供到子进程的输入和获得从子进程的输出。因为有些本机平台仅针对标准输入和输出流提供有限的缓冲区大小,如果读写子进程的输出流或输入流迅速出现失败,则可能导致子进程阻塞,甚至产生死锁。
当进程启动后,就会打开标准输出流和错误输出流准备输出,当进程结束时,就会关闭他们。在举例1中,由于标准输出流有数据需要输出,但是我们却没有读取其中的数据,标准输出流就会一直等待数据被读取,程序挂起。
举例2.处理标准输出流
public class RuntimeExecDemo { public static void main(String[] args) throws InterruptedException { Runtime runtime = Runtime.getRuntime(); Process process = null; try { process = runtime.exec("cmd /c dir", null, new File("g:/")); } catch (IOException e) { e.printStackTrace(); } try { BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream())); String line = null; while ((line = br.readLine()) != null) { System.out.println(line); } } catch (IOException e) { e.printStackTrace(); } int exitVal = process.waitFor(); System.out.println("Process exitValue: " + exitVal); } }
当我们处理了标准输出后,则程序可以正常运行了。但是,如果我们的命令是错误的,那么情况又会如何呢?即这里将dir修改成dira,然后执行。程序仍然可以正常运行,只不过结束的时候的exitVal不再是0。
为什么会出现这种情况呢?这里就是当我们执行程序的时候,先打开的是标准输出流,然后等待我们从中读取数据,而我们对需要读取的数据做了读取处理。那么当接下来打开错误输出流的时候,尽管没有被读取,但是却不再阻塞,程序异常终止。
但是,如果命令是正确的(即dira已经改回dir)再将process.getInputStream()修改成process.getErrorStream()呢?这次程序又一起挂起了。这是由于标准输出流是先打开并需要输出而,但是却并没有被读取;读取的是错误输出流,那么此时标准输出流的数据没有被读取导致程序不会结束。
为了解决这个问题,可以根据输出的实际先后,先读取标准输出流,然后读取错误输出流。
但是,很多时候不能很明确的知道输出的先后,特别是要操作标准输入的时候,情况就会更为复杂。这时候可以采用线程来对标准输出、错误输出和标准输入进行分别处理,根据他们之间在业务逻辑上的关系决定读取那个流或者写入数据。
针对标准输出流和错误输出流所造成的问题,还可以使用ProcessBuilder的redirectErrorStream()方法将他们合二为一,这时候只要读取标准输出的数据就可以了。
举例3.使用多线程
public class RuntimeExecDemo { public static void main(String[] args) { Runtime runtime = Runtime.getRuntime(); Process process = null; try { process = runtime.exec("cmd /c dir", null, new File("g:/")); } catch (IOException e) { e.printStackTrace(); } InputStream is = process.getInputStream(); InputStream es = process.getErrorStream(); StringBuffer out = new StringBuffer(128); StreamGobbler isGobbler = new StreamGobbler(is, "gbk", out); StringBuffer err = new StringBuffer(128); StreamGobbler errorGobbler = new StreamGobbler(es, "gbk", err); isGobbler.start(); errorGobbler.start(); int exitVal = -1; try { exitVal = process.waitFor(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("out : \r\n" + out.toString()); System.out.println("err : \r\n" + err.toString()); System.out.println("Process exitValue: " + exitVal); } }
class StreamGobbler extends Thread { InputStream is; String encoding = "utf-8"; StringBuffer result = new StringBuffer(); /** * * @param is process.getErrorStream() or process.getInputStream() * @param encoding default is "utf-8", if the result include chinese, need to use "gbk" */ StreamGobbler(InputStream is, String encoding, StringBuffer result) { this.is = is; this.encoding = encoding; this.result = result; } public void run() { try { InputStreamReader isr = new InputStreamReader(is, encoding); BufferedReader br = new BufferedReader(isr); String line=null; while ( (line = br.readLine()) != null) { result.append(line).append("\r\n"); } } catch (IOException e) { e.printStackTrace(); } } }
举例4.是用ProcessBuilder.redirectErrorStream()
public boolean redirectErrorStream()
通知进程生成器是否合并标准错误和标准输出。
如果此属性为 true,则任何由通过此对象的 start() 方法启动的后续子进程生成的错误输出都将与标准输出合并,因此两者均可使用 Process.getInputStream() 方法读取。这使得关联错误消息和相应的输出变得更容易。初始值为 false。
public class ProcessBuilderDemo { public static void main(String[] args) { ProcessBuilder pb = new ProcessBuilder("cmd", "/c", "dira"); pb.directory(new File("g:\\")); pb.redirectErrorStream(true); Process process = null; try { process = pb.start(); } catch (IOException e1) { e1.printStackTrace(); } try { BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream())); String line = null; while ((line = br.readLine()) != null) { System.out.println(line); } } catch (IOException e) { e.printStackTrace(); } int exitVal = -1; try { exitVal = process.waitFor(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Process exitValue: " + exitVal); } }
<<OVER>>
发表评论
-
闷葫芦的世界
2016-01-09 22:57 308工作几年,零零散散也整理了不少东西,但都是东一榔头西一棒槌的, ... -
JavaMail(一)
2011-04-26 18:04 1193浅谈邮件传输协议 SMTP(Simple Ma ... -
Tomcat配置SSL的双向认证
2011-04-26 16:58 2391证书保存在服务器端,用户通过浏览器访问时,需要 ... -
Tomcat配置SSL的客户端认证
2011-04-26 16:41 2403证书保存在服务器端,用户通过浏览器访问时,需要 ... -
Java实现国际化
2011-04-20 15:15 12761.根据不同语言环境使用不同文件 ... -
Java动态编译(一)
2011-04-18 18:10 7085一般情况下对java源文件的编译均是在代码完成 ... -
Java抽象类和接口
2011-04-18 15:34 2033一个Java接口(Interface)是一些方 ... -
Java线程(三)
2011-04-15 11:51 1176浅谈synchronized应何时使用 ... -
Java线程(二)
2011-04-15 10:23 950浅谈synchronized应用于类方法和类字面量之上 ... -
Java线程(一)
2011-04-14 11:29 931线程同步:synchronized方法和syn ... -
ClassLoader
2011-04-12 16:58 1146当运行Java程序时,首先运行JVM(java虚拟 ... -
NIO第二部分复用和编码
2011-04-08 14:46 762public abstract class Sel ... -
NIO第一部分缓冲区和通道
2011-04-08 14:40 1383系统运行的性 ... -
CLASSPATH和PATH
2011-04-06 13:45 2000J2SDK(Software Devel ...
相关推荐
JAVA反编译工具JAVA反编译工具JAVA反编译工具JAVA反编译工具JAVA反编译工具JAVA反编译工具JAVA反编译工具JAVA反编译工具JAVA反编译工具JAVA反编译工具JAVA反编译工具JAVA反编译工具JAVA反编译工具JAVA反编译工具JAVA...
java动态编译java源文件,并利用Instrumentation实现重定义class
java动态编译的几种技术介绍。JavaCompiler --JDK6 API的简介(java动态编译)
java 动态编译.java文件,动态运行类
添加动态执行的编译环境 options 是个集合,添加内容,字符集,classpath等 * 6.传入JavaFileObject的java文件,是个集合,创建JavaSourceObject实现这个接口,Kind.SOURCE.extension = '.java' * 7.创建任务并...
java 动态编译.java文件,动态运行类 _1.2
SpringBoot 应用动态编译 Java 源码并注入 Spring 容器,实现动态修改接口和抽象类的实现。注意,项目以 Jar 包形式启动时要在命令行引入 tools.jar 的包,IDEA下可直接调试。 基于接口、抽象类实现不停机动态调整...
本代码块为动态编译指定java文件,将编译后的class生成jar文件.调用示例为BuildRmi类
java 动态编译.java文件,动态运行类 _1.3
java内存动态编译执行
java动态编译 ,写了一个jsp在页面上编辑java代码,然后servlet动态编译并执行main方法
利用Java的动态编译、动态加载结合EasyRules实现业务规则的动态性的项目源码,具体详情请查看相关博客https://blog.csdn.net/qq_31142553/article/details/85013989
java反编译 java 反编译 java反编译 java 反编译 java反编译 java 反编译 java反编译 java 反编译 java反编译 java 反编译
Java的动态编译知识,真真在实际开发中并不是经常遇到。但是学习java动态编译有助于我们从更深一层次去了解java。对掌握jdk的动态代理模式,还有比如CGLIB,Spring 的AOP的原理就很有帮助。这样我们在学习其他一些开源...
Java语言-动态编译代码并热加载类,js热加载
JAVA反编译 JAVA反编译JAVA反编译
可以将java编译后的class文件或者jar包反编译出来,看到编译前的代码
NULL 博文链接:https://zheng12tian.iteye.com/blog/1488813
java动态编译源码并调用的三种方式,全部包含在内,并且有文档说明,还是相当不错的。
JAVA反编译插件文件