如何在Java 9中获取进程的命令行和参数

14

Java 9提供了一种很好的方式来获取Process的信息,但我仍然不知道如何获取进程的CommandLinearguments

Java 9提供了一种漂亮的方法来获取进程的信息,但我还不知道如何获取进程的CommandLinearguments

Process p = Runtime.getRuntime().exec("notepad.exe E:\\test.txt");
ProcessHandle.Info info = p.toHandle().info();
String[] arguments = info.arguments().orElse(new String[]{});
System.out.println("Arguments : " + arguments.length);
System.out.println("Command : " + info.command().orElse("")); 
System.out.println("CommandLine : " + info.commandLine().orElse(""));

结果:

Arguments : 0
Command : C:\Windows\System32\notepad.exe
CommandLine : 

但是我期望:

Arguments : 1
Command : C:\Windows\System32\notepad.exe
CommandLine : C:\Windows\System32\notepad.exe E:\\test.txt

1
为了进一步调试,请尝试将您的ProcessHandler p.toHandle() 替换为 ProcessHandle.current() 并执行,以查看是否在预期字段中获得一些值。主要是为了查看当前进程的处理程序是否合适。 - Naman
不幸,仍然一样。 - Viet
3个回答

11

看起来这个问题已经在JDK-8176725中报告了。以下是描述该问题的评论:

命令行参数不可通过非特权API供其他进程使用,因此Optional始终为空。API明确说明这些值是特定于操作系统的。如果将来参数可以通过Window API使用,那么实现可以进行更新。

顺便说一下,信息结构由本地代码填充;字段的赋值不出现在Java代码中。


是的,看起来这在Linux、MacOS上可以运行,但现在在Windows上不行。 - Viet
对于那个错误的解决方案还不是非常确定,但似乎它会被标记为一个“未来项目”。 - Naman
这个问题的当前状态是什么?它被标记为“已解决”,但似乎并非如此。 - LppEdd

4

JDK-8176725 表明这个功能在 Windows 上尚未实现。以下是一个简单但速度较慢的解决方法:

  /**
   * Returns the full command-line of the process.
   * <p>
   * This is a workaround for
   * <a href="https://dev59.com/K1YN5IYBdhLWcg3w4bhS#46768046">https://dev59.com/K1YN5IYBdhLWcg3w4bhS#46768046</a>
   *
   * @param processHandle a process handle
   * @return the command-line of the process
   * @throws UncheckedIOException if an I/O error occurs
   */
  private Optional<String> getCommandLine(ProcessHandle processHandle) throws UncheckedIOException {
    if (!isWindows) {
      return processHandle.info().commandLine();
    }
    long desiredProcessid = processHandle.pid();
    try {
      Process process = new ProcessBuilder("wmic", "process", "where", "ProcessID=" + desiredProcessid, "get",
        "commandline", "/format:list").
        redirectErrorStream(true).
        start();
      try (InputStreamReader inputStreamReader = new InputStreamReader(process.getInputStream());
           BufferedReader reader = new BufferedReader(inputStreamReader)) {
        while (true) {
          String line = reader.readLine();
          if (line == null) {
            return Optional.empty();
          }
          if (!line.startsWith("CommandLine=")) {
            continue;
          }
          return Optional.of(line.substring("CommandLine=".length()));
        }
      }
    } catch (IOException e) {
      throw new UncheckedIOException(e);
    }
  }

优秀的解决方法。要将其转换为等同于info.arguments()的字符串数组,然后必须对字符串进行标记化,注意带引号的字符串,例如使用https://dev59.com/qnA75IYBdhLWcg3wT3L8; 然后删除第一个元素,即命令名称。 - 0__

1

尝试使用ProcessBuilder代替Runtime#exec()

Process p = new ProcessBuilder("notepad.exe", "E:\\test.txt").start();

另一种创建流程的方式是:

...

(保留HTML,不解释)
Process p = Runtime.getRuntime().exec(new String[] {"notepad.exe", "E:\\test.txt"});

这是相同的结果。在更改为Runtime.getRuntime()之前,我已经尝试过了。 - Viet
你尝试过我提到的相同命令吗?或者 Process p = Runtime.getRuntime().exec("notepad.exe", new String[] {"E:\\test.txt"}); - Mykola Yashchenko
是的,我刚刚这样做了,结果也一样。我认为这是Java 9的一个bug。 - Viet

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