【问题标题】:Runtime.exec on argument containing multiple spacesRuntime.exec 在包含多个空格的参数上
【发布时间】:2011-10-04 22:07:07
【问题描述】:

如何进行以下运行?

public class ExecTest {
  public static void main(String[] args) {
    try {
      //Notice the multiple spaces in the argument
      String[] cmd = {"explorer.exe", "/select,\"C:\\New      Folder\\file.txt\""};

      //btw this works
      //String cmd = "explorer.exe /select,\"C:\\New Folder\\file.txt\"";

      //and surprisingly this doesn't work
      //String[] cmd = {"explorer.exe", "/select,\"C:\\New Folder\\file.txt\""};

      //Update: and (as crazy as it seems) the following also worked
      //String[] cmd = {"explorer.exe", "/select,\"C:\\New", "Folder\\file.txt\""};

      Runtime.getRuntime().exec(cmd);
    } catch (Exception e) {
        e.printStackTrace();
    }
  }
}

使用 Java 6。在 Vista x64 下测试。顺便说一句,获取执行的字符串(您必须使用字符串版本的 exec 来获取它)并在 Vista 开始菜单的 Search 字段中使用它会按预期运行。

【问题讨论】:

  • 第一种情况有错字吗?我怀疑在第二种“btw”情况下,/select 被奇怪地对待,因为它是 arg[0] 的一部分。提供 dir 作为 arg 将打开该文件夹。鉴于它们的名称都相同,您很容易错过它比您预期的低一个。我会将它们重命名为不同的。
  • 嗯,第一种和第二种情况是相同的命令。在这里,我只是演示了 exec 的数组版本 fails 在这种情况下,而字符串版本 work。路径就在那里,恐怕无关紧要,我可以使用任何东西.. thnx 回答

标签: java runtime exec spaces


【解决方案1】:

更好的方法是使用 ProcessBuilder 对象:

 Process p;
 p = new ProcessBuilder("/Applications/Sublime Text.app/Contents/MacOS/sublime_text", homeDir + _CURL_POST_PUT_CMDS).start();
 int exitValue = p.waitFor();
 if (exitValue != 0){
    System.out.println("Error to open " + homeDir + _CURL_POST_PUT_CMDS);
 }

【讨论】:

    【解决方案2】:

    对于您需要显示/选择命令的特定情况,我使用 cmd /c start 解决了 Windows 引用噩梦:

    String[] cmd = {"cmd", "/c", "start explorer.exe /select," + path};
    

    path 是 File 对象的绝对路径。

    【讨论】:

      【解决方案3】:

      解决文件问题的简单方法是 java.awt.Desktop 从 1.6 开始 示例:

         Desktop.getDesktop().open(new File(fullFileName));
      

      【讨论】:

        【解决方案4】:

        字符,-& 和双空格,加起来简直就是一场噩梦!

        "\\NAS\media\Music\Artistes\E\Earth, Wind & Fire\1992 - The eternal dance - Vol. 1 (1971-1975) 的所有答案都失败了('Vol. 1' 和 '(1971') 之间的双倍空格。

        我别无选择,只能写一个临时批处理文件:

           void openFolderOf( Album album ) {
              try {
                 final String path = album._playList.getParent();
                 final File batch = File.createTempFile( getClass().getSimpleName(), ".bat" );
                 try( PrintStream ps = new PrintStream( batch )) {
                    ps.println( "explorer.exe \"" + path + '"' );
                 }
                 Runtime.getRuntime().exec( batch.getAbsolutePath());
              }
              catch( final Throwable t ) {
                 t.printStackTrace();
              }
           }
        

        注意:在 cmd.exe 上,explorer "\\NAS..." 行运行良好,但不适用于 Runtime.exec() 或 ProcessBuilder。

        【讨论】:

        • 这也是唯一对我有用的方法,谢谢,但我改用缓冲区写入器: File batch = File.createTempFile( "bat" + cuid, ".bat" ); BufferedWriter txt = new BufferedWriter(new FileWriter(batch.getAbsolutePath())); txt.write(winrarcmd); txt.close();
        【解决方案5】:

        奇迹,它奏效了!

        不要问我为什么,但是当我在互联网上进行了相当长的神经破坏研究后,几乎要放弃并使用临时批处理文件作为解决方法时,我忘记添加 /select,命令的参数,谁会想到,以下适用于我的 Win 7 32 位系统。

        String param = "\"C:\\Users\\ME\\AppData\\Local\\Microsoft\\Windows\\Temporary Internet Files\\\"";
        try {
            String[]commands = new String[]{"explorer.exe", param};
            Process child = Runtime.getRuntime().exec(commands);
        } catch (IOException e1) {
            System.out.println("...");
        }
        

        一般解决方案:

        prunge 在他的帖子 (http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6511002) 中提到的错误数据库的解决方案对我来说效果很好。

        原因:

        显然,问题在于 java 在实际执行命令字符串之前对某些字符的注释。 您必须通过标记您的命令字符串来自己进行注释,以防止错误的 java 启动并搞砸一切。

        如何解决:

        因此,在我的情况下,我必须执行以下操作(标记我的命令字符串,以便 字符串内没有空格):

        String param[] = {
            "explorer.exe",
            "/select,C:\\Users\\ME\\AppData\\Local\\Microsoft\\Windows\\Temporary",
            "Internet",
            "Files\\"};
        
        try {
            Process child = Runtime.getRuntime().exec(param);
        } catch (IOException e1) {
            System.out.println("...");
        }
        

        如您所见,我基本上在出现空格的地方开始了一个新字符串,因此“临时 Internet 文件”变成了“临时”、“Internet”、“文件”。

        【讨论】:

          【解决方案6】:

          好的,这不仅仅是一个更新,也是一个答案,所以我将它作为一个提交。根据我能找到的所有信息,理论上应该这样做:

          String[] cmd = {"explorer.exe", "/select,\"C:\New", "", "", "", "", "", "", "文件夹\文件。 txt\""};

          多个空格已被拆分为空字符串,并使用了数组版本的 exec。 使用上面的数组,我在 java.lang.ProcessImpl 的第 50-75 行中调试了循环,其中最终构造了一个字符串。结果字符串是:

          explorer.exe /select,"C:\New       文件夹\file.txt"

          这是作为第一个参数传递给 ProcessImpl 的 native create 方法(第 118 行同一类)的参数,它似乎无法正确运行此命令

          所以我猜这一切都到此结束了……很遗憾。

          Thnx prunge 指出了 java 错误。 感谢大家的时间和兴趣!

          【讨论】:

          • 现在我正在寻找替代方法来做到这一点。使用 jni 是一种选择,但会导致 32 位或 64 位系统的应用程序版本不同。目前我正在研究一个疯狂的解决方案,简而言之就是打开一个bat文件,写入cmd并执行bat。平均总时间为 45 毫秒。太好了,explorer.exe 进程大约需要 500 毫秒,所以这并不明显。同样通过这种方式,您可以从字面上执行所有操作。 wdyt?
          【解决方案7】:

          除非命令行极其简单,否则始终使用 Runtime.exec(String[]),而不是 Runtime.exec(String)。

          【讨论】:

          • 我将不得不根据我的情况不同意,因为使用数组版本失败而字符串版本有效。您可以取消注释我的代码并自己查看。我对标记器及其产生的问题了如指掌,但在这种情况下并没有帮助。这真的是一个简单的命令,对吧?所以我的意见是......使用 Runtime.exec,使用你设法让它工作的任何东西!
          • Minos 那是因为你已经通过引用等方式补偿了单参数版本中的解析。如果你使用另一个,你只需要传递实际值,不需要引号,不需要事后猜测.
          • 不明白。如何在不转义引号的情况下编写它? String[] cmd = {"explorer.exe", "/select,\"C:\\New Folder\\file.txt\""};。如果你不引用路径,让 exec 为你做,那么你会得到参数的 /select, 部分也被引用。 Explorer 绝对不会喜欢这样的。即使这是唯一具有这种尴尬的命令(不是这种情况),这仍然看起来有问题..当字符串版本完全按照人们的预期工作时
          • @Minos {"explorer.exe", "/select", "C:\\New Folder\\file.txt"}.
          • 这将在以下命令中结束:explorer.exe /select "C\New Folder\file.txt"。这,简单地说是错误。这不是我要的命令。 /select 和路径之间有一个空格。同样在您的示例中,您错过了 /select 之后的逗号,但无论如何主要问题是您引入的空间。检查资源管理器是否可以处理额外的空间,我看到它可以,所以我会给你的答案加分。但总的来说,我发现我无法准确执行我想要的命令很烦人。为什么我的字符串不能保持原样..
          【解决方案8】:

          可能是 Java 错误。看: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6511002

          出于好奇做了一些调试,我认为java.lang.ProcessImpl 中的事情正在变得不稳定(参见构造函数)。注意到当它真正调用底层 Windows API 时,字符串变成了

          explorer.exe "/select,"c:\New Folder\test.txt""

          所以这可以解释为什么,至于解决方法,请参阅错误数据库链接。

          【讨论】:

          • 这不是错误:它是 RFE(增强请求)。具体来说,它是记录现有行为的请求。
          • 谢谢修剪!我也进行了一些调试,并与您得出了完全相同的结论,多个空格被修剪(我猜是通过''上的标记器),而您最终得到了一个空格。无论您使用字符串版本还是数组版本的 exec。 java.lang.ProcessBuilder 的第 452 行的断点揭示了这一点。我将查看您提到的错误并发布任何发现。 Thnx 非常非常非常
          【解决方案9】:

          先使用new File(pathName).canExecute()检查是否可执行

          编辑:

          public static void runAll(String... cmd)
          {
              for(String s : cmd)
              {
                  try
                  {
                      Runtime.getRuntime().exec(cmd);
                  }
                  catch(Exception e)
                  {
                      e.printStackTrace();
                  }
              }
          }
          

          然后你可以像这样使用它:runAll("explorer.exe", "taskmgr.exe");

          【讨论】:

          • 是的 explorer 是 vista 中的可执行文件。你不是说探险家吗?另外,请看我的cmets。其他命令是如何工作的?
          • @Minos 我不太理解你的问题,但看到更新,这是你要找的吗?
          • 很抱歉,您是否尝试运行我的主程序?我的问题不是关于如何构建它,而是为什么我发布的那个完全简单的代码块没有按预期运行。谢谢..
          • @Minos 好的。好吧,也许你必须以管理员身份运行程序
          • 当然,但是为什么在非多个空格的情况下我也不需要成为管理员?当只有单个空格时它如何工作?反正我试过了..
          猜你喜欢
          • 1970-01-01
          • 2018-05-30
          • 2018-07-08
          • 2017-03-23
          • 1970-01-01
          • 2021-05-28
          • 1970-01-01
          • 1970-01-01
          • 2010-10-22
          相关资源
          最近更新 更多