Java魔法堂:找外援的利器——Runtime.exec详解

简介:

一、前言                                

 Java虽然五脏俱全但总有软肋,譬如获取CPU等硬件信息,当然我们可以通过JNI调用C/C++来获取,但对于对C/C++和Windows API不熟的码农是一系列复杂的学习和踩坑过程。那能不能通过简单一些、学习成本低一些的方式呢?答案是肯定的,在功能实现放在首位的情况下,借他山之石是最简洁有力的做法。而 Runtime.exec方法 就为我们打开这么的一条路了。

 

二、认识 java.lang.Runtime.exec方法                     

  作用:用于调用外部程序,并重定向外部程序的标准输入、标准输出和标准错误到缓冲池。功能就是和windows的“运行”一样啦。

  

  方法重载:

      exec(String command) ,调用外部程序,入参command为外部可执行程序的启动路径或命令。

      exec(String[] cmdArray) ,调用外部程序,入参cmdArray的元素将组合成为一条完整的外部可执行程序的启动路径或命令。

      exec(String command, String[] envp) ,在调用外部程序之前设置系统环境变量,该变量仅供command入参使用,envp每个元素为一个系统环境变量,并且字符串格式为“环境变量名=环境变量值”。

       exec(String command, String[] envp, File dir) , 除了设置系统环境变量外,还通过入参dir设置当前工作目录。

  实例 —— 在当前目录执行dir命令,并将结果保存到c:\dir.txt文本文件中:

  前提:假设当前用户的家目录为c:\user\fsjohnhuang

  c:\user\fsjohnhuang下的目录结构

c:\user\fsjohnhuang 
|--jottings 
|--test.txt

  d:\test下的目录结构

d:\test
|--movies
|--readme.txt

  代码片段

复制代码
Runtime r = Runtime.getRuntime();
try{
  Process proc = r.exec("cmd /c dir > %dest%", new String[]{"dest=c:\\dir.txt", new File("d:\\test")});
  int exitVal = proc.waitFor(); // 阻塞当前线程,并等待外部程序中止后获取结果码
  System.out.println(exitVal == 0 ? "成功" : "失败");
}
catch(Exception e){
  e.printStackTrace();
}
复制代码

  执行代码后查看c:\dir.txt文件内容如如下:

复制代码
驱动器 D 中的卷没有标签。
 卷的序列号是 8074-B214

 D:\test 的目录

2014/09/22  14:45    <DIR>          movies
2014/03/31  17:14             8,642 readme.txt
复制代码

 

三、注意点                              

  1.  Runtime.exec() 不是cmd或shell环境,因此无法直接调用dir等命令。若要调用命令行下的命令,请参考第2节的实例。

  2.  通过 Process实例.getInputStream() 和 Process实例.getErrorStream() 获取的输入流和错误信息流是缓冲池向当前Java程序提供的,而不是直接获取外部程序的标准输出流和标准错误流。

  

   而缓冲池的容量是一定的,因此若外部程序在运行过程中不断向缓冲池输出内容,当缓冲池填满,那么外部程序将暂停运行直到缓冲池有空位可接收外部程序的输出内容为止。(采用xcopy命令复制大量文件时将会出现该问题)

   解决办法就是当前的Java程序不断读取缓冲池的内容,从而为腾出缓冲池的空间。

 

四、绝对是坑                              

  为解决第3节第2点注意事项中提及的问题。我们可以通过下列两种方式处理

复制代码
Runtime r = Runtime.getRuntime();
try{
  Process proc = r.exec("cmd /c dir"); // 假设该操作为造成大量内容输出
  // 采用字符流读取缓冲池内容,腾出空间
  BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream(), "gbk")));
  String line = null;
  while ((line = reader.readLine()) != null){
     System.out.println(line);
  }

  // 或采用字节流读取缓冲池内容,腾出空间
  // ByteArrayOutputStream pool = new ByteArrayOutputStream();
  // byte[] buffer = new byte[1024];
  // int count = -1;
  // while ((count = proc.getInputStream().read(buffer)) != -1){
  //   pool.write(buffer, 0, count);
  //   buffer = new byte[1024];
  // }
  // System.out.println(pool.toString("gbk"));

  int exitVal = proc.waitFor();
  System.out.println(exitVal == 0 ? "成功" : "失败");
}
catch(Exception e){
  e.printStackTrace();
}
复制代码

这里要注意一个坑:外部程序在执行结束后将会自动关闭,否则不管是字符流还是字节流均由于既读不到数据,又读不到流结束符而出现阻塞Java进程运行的情况。

而 cmd /c 就是告诉cmd环境进程,当执行完成后关闭自身。

 

五、总结                                  

  用适当的工具做适当的事, Runtime.exec方法 让我们功能实现的手段更灵活了!

  尊重原创,转载请注明来自:http://www.cnblogs.com/fsjohnhuang/p/4081445.html  ^_^肥仔John

 

六、参考                                  

  http://fuliang.iteye.com/blog/574260

如果您觉得本文的内容有趣就扫一下吧!捐赠互勉!


本文转自^_^肥仔John博客园博客,原文链接:http://www.cnblogs.com/fsjohnhuang/p/4081445.html,如需转载请自行联系原作者

相关文章
|
JavaScript 安全 前端开发
《Java安全编码标准》一2.8 IDS07-J不要向Runtime.exec()?方法传递非受信、未净化的数据
本节书摘来自华章出版社《Java安全编码标准》一书中的第2章,第2.8节,作者 (美)Fred Long,Dhruv Mohindra,Robert C. Seacord,Dean F. Sutherland,David Svoboda,更多章节内容可以访问云栖社区“华章计算机”公众号查看
4977 0
|
8天前
|
存储 Java 数据库连接
java多线程之线程通信
java多线程之线程通信
|
9天前
|
安全 Java 开发者
深入理解Java并发编程:线程安全与性能优化
【4月更文挑战第9天】本文将深入探讨Java并发编程的核心概念,包括线程安全和性能优化。我们将详细解析Java中的同步机制,包括synchronized关键字、Lock接口以及并发集合等,并探讨它们如何影响程序的性能。此外,我们还将讨论Java内存模型,以及它如何影响并发程序的行为。最后,我们将提供一些实用的并发编程技巧和最佳实践,帮助开发者编写出既线程安全又高效的Java程序。
22 3
|
12天前
|
设计模式 安全 Java
Java并发编程实战:使用synchronized关键字实现线程安全
【4月更文挑战第6天】Java中的`synchronized`关键字用于处理多线程并发,确保共享资源的线程安全。它可以修饰方法或代码块,实现互斥访问。当用于方法时,锁定对象实例或类对象;用于代码块时,锁定指定对象。过度使用可能导致性能问题,应注意避免锁持有时间过长、死锁,并考虑使用`java.util.concurrent`包中的高级工具。正确理解和使用`synchronized`是编写线程安全程序的关键。
|
10天前
|
Java
Java 并发编程:深入理解线程池
【4月更文挑战第8天】本文将深入探讨 Java 中的线程池技术,包括其工作原理、优势以及如何使用。线程池是 Java 并发编程的重要工具,它可以有效地管理和控制线程的执行,提高系统性能。通过本文的学习,读者将对线程池有更深入的理解,并能在实际开发中灵活运用。
|
8天前
|
算法 Java 开发者
Java中的多线程编程:概念、实现与性能优化
【4月更文挑战第9天】在Java编程中,多线程是一种强大的工具,它允许开发者创建并发执行的程序,提高系统的响应性和吞吐量。本文将深入探讨Java多线程的核心概念,包括线程的生命周期、线程同步机制以及线程池的使用。接着,我们将展示如何通过继承Thread类和实现Runnable接口来创建线程,并讨论各自的优缺点。此外,文章还将介绍高级主题,如死锁的预防、避免和检测,以及如何使用并发集合和原子变量来提高多线程程序的性能和安全性。最后,我们将提供一些实用的性能优化技巧,帮助开发者编写出更高效、更稳定的多线程应用程序。
|
6天前
|
安全 算法 Java
深入理解Java并发编程:线程安全与性能优化
【4月更文挑战第11天】 在Java中,高效的并发编程是提升应用性能和响应能力的关键。本文将探讨Java并发的核心概念,包括线程安全、锁机制、线程池以及并发集合等,同时提供实用的编程技巧和最佳实践,帮助开发者在保证线程安全的前提下,优化程序性能。我们将通过分析常见的并发问题,如竞态条件、死锁,以及如何利用现代Java并发工具来避免这些问题,从而构建更加健壮和高效的多线程应用程序。
|
10天前
|
Java
Java并发编程:深入理解线程池
【4月更文挑战第7天】在现代软件开发中,多线程编程已经成为一种不可或缺的技术。为了提高程序性能和资源利用率,Java提供了线程池这一强大工具。本文将深入探讨Java线程池的原理、使用方法以及如何根据实际需求定制线程池,帮助读者更好地理解和应用线程池技术。
15 0
|
2天前
|
设计模式 运维 安全
深入理解Java并发编程:线程安全与性能优化
【4月更文挑战第15天】在Java开发中,多线程编程是提升应用程序性能和响应能力的关键手段。然而,它伴随着诸多挑战,尤其是在保证线程安全的同时如何避免性能瓶颈。本文将探讨Java并发编程的核心概念,包括同步机制、锁优化、线程池使用以及并发集合等,旨在为开发者提供实用的线程安全策略和性能优化技巧。通过实例分析和最佳实践的分享,我们的目标是帮助读者构建既高效又可靠的多线程应用。
|
4天前
|
Java 程序员 编译器
Java中的线程同步与锁优化策略
【4月更文挑战第14天】在多线程编程中,线程同步是确保数据一致性和程序正确性的关键。Java提供了多种机制来实现线程同步,其中最常用的是synchronized关键字和Lock接口。本文将深入探讨Java中的线程同步问题,并分析如何通过锁优化策略提高程序性能。我们将首先介绍线程同步的基本概念,然后详细讨论synchronized和Lock的使用及优缺点,最后探讨一些锁优化技巧,如锁粗化、锁消除和读写锁等。