【问题标题】:Runtime.exec() returning nullRuntime.exec() 返回 null
【发布时间】:2021-04-27 00:57:17
【问题描述】:

我在这个网站上看到了类似的问题,但似乎没有一个能够解决/解决我的问题,所以我认为我的程序有一些特别的问题。我正在尝试执行一个非常简单的命令,即从文本字段输入中获取一个进程名称字符串,并将其连接到一个命令以返回并打印窗口的标题。这是我的代码:

        String line;
        Process p = null;
        try
        {
            String command = "tasklist /v /fo list /fi \"imagename eq  " + tf.getText().trim() + "*\"| find /i  \"window title:\"\n";
            p = Runtime.getRuntime().exec(command);

            BufferedReader input =
                    new BufferedReader(new InputStreamReader(p.getInputStream()));

            System.out.println(command);
            while ((line = input.readLine()) != null)
            {
                line = line.trim();
                System.out.println(line);

            }
            System.out.println("done");
        }
        catch (IOException ioException)
        {
            ioException.printStackTrace();
        }

但是,InputStream 返回的行始终为空,即使我将 .exec() 中使用的命令放入 cmd(我打印了它,所以我知道它们完全相同),它可以正常工作,尽管在5 秒左右的延迟。我尝试了 2 个不同的进程名称,它们都在 cmd 上工作,但在这个 java 程序中没有。这是上面代码的输出,以防万一(空行可能来自命令字符串末尾的 \n):

tasklist /v /fo list /fi "imagename eq  notepad*"| find /i  "window title:"

done

我尝试在调用 .exec() 后添加 p.waitFor(),但这似乎并没有改变任何东西。那么我在这里做错了什么?

【问题讨论】:

  • 也许你读错了流。该命令可能正在打印到标准错误,而不是标准输出。合并它们通常是个好主意,为此您需要使用ProcessBuilder
  • 请阅读 Windows 内核库函数 CreateProcess 的 Microsoft 文档,Runtime.getRuntime().exec() 在 Windows 上使用它来运行可执行文件。此函数不会在当前目录和环境变量PATH 的所有目录中搜索名称为tasklist 的文件,其中环境变量PATHEXT 的文件扩展名为cmd.exepowershell.exe、@987654331 @ 和 wscript.exe 做。这是在文档中明确写的。
  • find 的完整限定文件名是%SystemRoot%\System32\find.exe。命令行%SystemRoot%\System32\tasklist.exe /V /FO LIST /FI "IMAGENAME eq notepad*"| %SystemRoot%\System32\find.exe /I "window title:"的执行将需要%SystemRoot%\System32\cmd.exe的执行,因为CMD重定向运算符|与命令行%SystemRoot%\System32\cmd.exe /D /C "%SystemRoot%\System32\tasklist.exe /V /FO LIST /FI "IMAGENAME eq notepad*"| %SystemRoot%\System32\find.exe /I "window title:""
  • 但由于某些原因,最好只使用%SystemRoot%\System32\tasklist.exe /V /FO LIST /FI "IMAGENAME eq notepad*"而不使用ProcessHandle.allProcesses(),并使用Java代码过滤捕获的输出,以将对其他可执行文件及其配置的依赖降至最低。是的,cmd.exe 执行是可以配置的,而且经常被错误配置,导致应用程序在运行(通常是不必要的)Windows 命令处理器 cmd.exe 时出现很多麻烦,直到用户在专家的帮助下修复错误配置。
  • 所以Runtime.exec()不是“返回空值”,但是将进程的标准输出作为行读取返回空值。这仅意味着它在其标准输出上没有产生任何内容。准确。

标签: java cmd process tasklist


【解决方案1】:

您在启动该命令时遇到了两个问题。首先,您忽略了错误流,因此看不到实际问题。

p = Runtime.getRuntime().exec(command); 替换为ProcessBuilder 以访问错误消息:

ProcessBuilder pb = new ProcessBuilder(command);
pb.redirectErrorStream();
p = pb.start();

这会告诉你tasklist 不是一个进程。通常使用完整路径名可以修复这种类型的错误,但是当您使用管道时,必须将整个命令发送到 CMD.EXE 以正确解释管道组件。运行 CMD.EXE 然后你的管道命令:

ProcessBuilder pb = new ProcessBuilder("cmd.exe", "/c", command);
pb.redirectErrorStream();
p = pb.start();

打印:

tasklist /v /fo list /fi "imagename eq  notepad*"| find /i  "window title:"

Window Title: Notepad++
done

通过简单的传输也更容易读取 STDOUT:

try(var stdout = p.getInputStream()) {
    stdout.transferTo(System.out);  // or where-ever
}

【讨论】:

  • 感谢您的清晰解释!我知道我必须以某种方式使用 ProcessBuilder,但不熟悉并且有点困惑。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-21
相关资源
最近更新 更多