`

Java调用WMIC命令的方法阻塞

阅读更多
转自:http://blog.csdn.net/ragic/article/details/5583164
今天要写个远程重启服务的功能,为了开发速度,暂时定为Java代码+WMIC命令的方法,简单的说,就是利用Java调用本机应用程序的方法。涉及到的Java类有java.lang包里面的Runtime、Process、ProcessBuilder三个类,以及wmic中重启服务的命令。因为之前也写过这方面的东西,所以很习惯性的写出了代码:
    Process p = Runtime.getRuntime().exec("wmic ...");
    BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
    String tmp = null;
    
    while ((tmp = br.readline()) != null) {
        System.out.println(tmp);
    }
    int exitValue = p.waitfor();

运行,结果发现程序不能退出,Debug发现程序阻塞在br.readline()中了,强制结束程序,发现重启服务的命令正常下下去了,去掉程序中获得标准输出的地方和获得返回结果的地方,命令也能正常下去,而且正常退出。
    为什么程序会阻塞呢?Google了一下,发现了大家的解释,应该也是比较权威的解释吧:每个进程都有自己的标准输入、标准输出、标准错误输出,对于某些依赖于OS的进程,可能其输出缓冲区很小,如果不能及时的读出(标准输出、标注错误输出),将导致进程不能正常退出。我的程序中标准输出已经读了,显然原因不是这个,难道是错误输出缓冲区中的数据没有读出导致的?带着这个疑问,对程序作了一些更改:
    ProcessBuilder pb = new ProcessBuilder("wmic",...);
    pb.redirectErrorStream(true);
    Process p = pb.start();
    BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
    String tmp = null;
    
    while ((tmp = br.readline()) != null) {
        System.out.println(tmp);
    }
    int exitValue = p.waitfor();

编译运行,发现还是有问题,依然还是阻塞。又google了一下,大家的评论大多还是关于标准输出和标准错误输出,那这程序应该是没有问题了。后来在cmd中敲入wmic的命令,发现wmic命令敲入以后会进入一个自有的提示符中,难道是因为标准输入的问题。后来又google了一下,验证了我的猜想,果然是因为wmic进程会等待标准输入,而程序中没有处理标准输入的地方,是标准输入阻塞了进程的退出,修改代码:
    ProcessBuilder pb = new ProcessBuilder("wmic",...);
    pb.redirectErrorStream(true);
    Process p = pb.start();
    p.getOutputStream().close();
    BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
    String tmp = null;
    
    while ((tmp = br.readline()) != null) {
        System.out.println(tmp);
    }
    int exitValue = p.waitfor();

编译运行,程序成功执行。果然是标准输入的原因。
    后来执行的过程中换了一个服务的名称,发现执行失败(能够正常退出,但是返回的结果是“无效动作”),但是同样的命令,在命令行中执行成功,而且直接适用Runtime.exec()方法中写入整个命令也能够执行成功,难道是ProcessBuilder的错误,ProcessBuilder构造函数有两个:
    ProcessBuilder(List<String> command)
          利用指定的操作系统程序和参数构造一个进程生成器。
    ProcessBuilder(String... command)
          利用指定的操作系统程序和参数构造一个进程生成器。
    找到ProcessBuilder的源代码,发现了对List<String>的解析方法:JDK将List中的所有字符串用空格连接,对list中的每个字符串JDK先判断串中是否包含空格,如果包含空格,用双引号将该字符串引起来,再拼到前面字符串的后面(应该是为了解决路径中包含空格的问题),可恰好Wmic命令的参数中有一段是name="ServiceName",如果ServiceName中包换空格,JDK就会把name="service name"的外层加一个双引号,导致wmic不能解析该命令了。
    问题终于全都解决了,耗费了多半天的时间,不过收获总是有的,这里总结一下,在使用Java调用外部命令的时候,一定要注意对标准输出、标准输入和错误输出的处理。对于一般的命令,只需要将标准输出和错误输出合并,一起读出来或者在另外的线程中读出来,而对于一些特殊的命令,还有处理标准输入。建议即使不使用标准输入,先close了,总是不会出错了。另外,使用ProcessBuilder时要注意它的空格处理方式是否是你想要的,如果不是,就不能用ProcessBuilder了,直接使用Runtime.exec()就好了。
分享到:
评论
1 楼 xiaohuafyle 2012-06-07  
都收不到评论的

相关推荐

    修复windows下不能使用wmic命令的脚本

    WMIC扩展WMI(Windows Management Instrumentation,Windows管理工具) ,提供了从命令行接口和批命令脚本执行系统管理的支持。非常好用命令,这个脚本用于修复wmic不能使用的问题

    WMIC-Java:可以执行 WMIC 和命令行参数。 需要适当的 GUI 和需要管理员权限的工作命令

    WMIC-Java 可以执行 WMIC 和命令行参数。 需要适当的 GUI 和需要管理员权限的工作命令。 由一个主方法和来自 3 ... 可以使用 WMIC 收集来自计算机的许多有用信息,因此我认为看看 java 是否可以执行这些命令会很有趣。

    修复windows下不能使用wmic命令.bat

    WMIC扩展WMI(Windows Management Instrumentation,Windows管理工具) ,提供了从命令行接口和批命令脚本执行系统管理的支持。非常好用命令,这个脚本用于修复wmic不能使用的问题

    WMIC命令详解

    ### WMIC命令详解 #### 背景与概念 WMIC(Windows Management Instrumentation Command-line)作为微软在Windows Server 2003中推出的一种全新的命令行管理工具,结合了WMI的强大功能与命令行的简洁特性。对于那些...

    wmic.c C语言实现WMI

    wmic.c C语言实现WMI

    wmic命令行介绍及使用.pdf

    此外,WMIC还可以用于创建和管理计划任务,实现自动化攻击,甚至进行横向移动,比如通过WMIC连接到其他系统执行命令。 由于WMIC的强大功能和便捷性,安全专业人员必须对其有深入理解,以便于防御和对抗潜在的安全...

    Java调用外部程序命令

    ### Java调用外部程序命令详解 #### 一、引言 在进行系统集成或自动化脚本编写时,经常需要从Java程序中调用外部程序或命令。这种需求常见于多种场景,例如远程服务管理、批处理操作等。本文将详细介绍如何使用...

    用于Wmic命令行无效情况下的补丁

    4. "Wmic补丁使用说明.txt" - 这是一个文本文件,提供了关于如何安装和使用这个补丁的详细步骤和注意事项。用户在应用补丁前应仔细阅读此文件,确保正确无误地进行操作。 综上所述,这个压缩包提供的补丁是为了解决...

    wmic实例应用

    使用以下命令可以查看磁盘的属性: ``` wmic logicaldisk list brief ``` 这将显示所有磁盘的属性。如果要查看特定磁盘的属性,可以使用以下命令: ``` wmic logicaldisk where name="c:" get deviceid,size,...

    wmic教程命令收集.pdf

    使用以下命令可以查看 BIOS 的版本和型号: `wmic bios get Manufacturer,Name` 计算机系统管理 WMIC 允许用户访问和管理计算机系统的各种组件,例如查看系统启动选项、查看工作组/域等。使用以下命令可以查看...

    wmic取硬件信息模块.rar

    **WMIC取硬件信息的使用方法** 在命令行中,你可以输入`wmic`命令后接不同的类(Class)来获取特定的硬件信息。例如: - `cpu` 获取CPU信息 - `memorychip` 获取内存条信息 - `diskdrive` 获取硬盘信息 - `...

    WMIC:从命令行对Windows的全面管理

    别名机制可以将用户在命令行上输入的一些简单命令转换为预定义的操作,比如使用一个简单的WMIC别名Get命令来构造复杂的WMI查询语言(WQL)命令。这意味着用户无需深入了解WQL语法即可实现复杂的查询。 例如,使用`...

    ProcessBuilder非阻塞是调用

    ProcessBuilder 非阻塞是调用是指在 Java 中使用 ProcessBuilder 类来执行外部命令或程序时,如何实现非阻塞调用。 在 Java 中,使用 ProcessBuilder 类可以执行外部命令或程序,例如执行系统命令、运行可执行文件...

    命令查看主板显卡

    ### 一、使用`dxdiag`命令查看显卡信息 #### 1.1 `dxdiag`简介 `dxdiag`是Microsoft提供的一个诊断工具,用于检测DirectX系统的运行状态。它可以显示关于计算机上安装的DirectX组件的详细信息,包括显卡型号、驱动...

    wmic实例应用修改版

    - **动词**:表示要对对象进行的操作,如GET(获取信息)、SET(设置信息)、CALL(调用方法)、LIST(列出信息)等。 - **副词**:动词的参数,用于细化动词的操作,如显示详细或简要信息。 - **动词开关**:进一步...

    易语言源码易语言wmic取硬件信息模块源码.rar

    在这个源码模块中,开发者可能使用了易语言的系统调用功能来执行WMIC命令,通过解析WMIC返回的结果来获取硬件信息。系统调用允许易语言程序直接与操作系统进行交互,执行特定的系统命令。例如,可能会使用类似于...

    Java如何调用可执行文件和批处理命令.doc

    Java调用可执行文件和批处理命令是Java开发中常见的需求,特别是在与系统交互或集成外部工具时。本文将详细讲解两种主要的方法:调用exe文件和通过转换批处理文件来间接调用。 首先,调用Windows下的可执行文件...

Global site tag (gtag.js) - Google Analytics