使用ProcessBuilder/Runtime.exec()启动的外部进程在XP上失败,在Win 7上工作

6

我正在开发一个Java程序,需要获取计算机序列号、CPU序列号等信息。在Windows系统中,使用WMI接口查询是获取这些信息最好的方式。通过命令行进行查询的标准方法是:

wmic bios get serialnumber

输出结果:

SerialNumber
WWV46RT609A3467173E

将其翻译为Java,我使用了Runtime.exec()和ProcessBuilder: (上面的注释Process p是我之前所做的)。这里,组件和项对应于上面命令中的“bios”和“serialnumber”。

    String ret = "";
    ProcessBuilder pb = new ProcessBuilder("wmic", component, "get", item);
    pb.redirectErrorStream(true);
    // Process p = Runtime.getRuntime().exec(
    // "wmic " + component + " get " + item);
    Process p = pb.start();
    InputStreamReader isr = new InputStreamReader(p.getInputStream());
    BufferedReader input = new BufferedReader(isr);
    String str;
    while ((str = input.readLine()) != null) {
        if (str.equalsIgnoreCase(item) || StringUtils.isBlank(str)) {
            continue;
        }
        ret = str.trim();
    }
    input.close(); 
    isr.close();
    System.out.println(ret); 

这段代码在Windows 7上运行得非常完美,但是在Windows XP上却卡住了。使用命令行中的wmic在两个操作系统上都可以正常工作。 我在这里读到,处理调用进程的标准输出和标准错误输出时会出现问题,因此需要调用redirectErrorStream()。

为什么它在Windows 7上无缺陷地工作,而在XP上失败了?除了生成一个单独的线程(也就是'StreamGobbler')之外,还有其他方法吗?(链接的示例相当古老,先于ProcessBuilder类及其redirectErrorStream()调用。)


当进程“挂起”时,请始终获取堆栈跟踪(例如 jstack)。另外需要说明的是,在执行 ret = str.trim() 后需要加上 break,但我猜在 XP 上这个命令只会进入交互模式。 - bestsss
如果你提出的问题很明显第一条评论可能是“阅读JavaWorld文章”,并且你已经展示了已经阅读它的证据,那么我会给你加1分。 :) - Andrew Thompson
@Andrew:谢谢 :) 我通常只有在完全没有其他选择(已经在Google上搜索过相关主题)或者我正在处理的问题比较晦涩或者文档不够详细(就像我最近关于NSIS的所有问题一样)时才会发布问题。 - Rex
2个回答

7

希望您已经解决了这个问题。如果没有,以下是您需要做的事情。首先,我也遇到了同样的问题,并发现这是bufferedReader的问题。它会陷入死锁状态,导致Windows XP挂起。解决方法是通过在命令后添加"<NUL"来模拟缓冲读取器的行尾(eof)。

 String[] command = {"CMD", "/C", "WMIC COMPUTERSYSTEM GET USERNAME <NUL "} and executing this command. 

+1。这个答案对Minecraft社区有很大帮助!许多Minecraft工具必须运行其他应用程序,在Windows XP上遇到了完全相同的问题。 - Cybis

0

你需要使用线程来捕获输出(标准和错误)。

你也可以查看这个Apache库


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接