【问题标题】:ProcessBuilder vs Runtime.exec()ProcessBuilder 与 Runtime.exec()
【发布时间】:2011-04-29 04:02:36
【问题描述】:

我正在尝试使用 Inkscape 的命令行功能在 Java 中创建一个前端应用程序来处理批量 SVG 转换。我正在获取并更新来自https://sourceforge.net/projects/conversionsvg/ 的代码。原始开发人员通过 Runtime.getRuntime().exec(String) 处理调用 Inkscape 的方式。我遇到的问题是使用methodA和methodB之间的一些不一致。我创建了一个简单的 java 测试项目来演示正在执行的不同操作。

CallerTest.java

package conversion;

import java.io.IOException;

public class CallerTest {
  
    static String pathToInkscape = "\"C:\\Program Files\\Inkscape\\inkscape.exe\"";  
    
    public static void main(String[] args) {
      
      ProcessBuilderCaller processBuilder = new ProcessBuilderCaller();
      RuntimeExecCaller runtimeExec = new RuntimeExecCaller();
      
      // methodA() uses one long command line string
      try {
        
        String oneLongString_ProcessBuilder = pathToInkscape + " -f \"C:\\test.svg\" -D -w 100 -h 100 -e \"C:\\ProcessBuilder-methodB.png\"";
        String oneLongString_RuntimeExec =    pathToInkscape + " -f \"C:\\test.svg\" -D -w 100 -h 100 -e \"C:\\RuntimeExec-methodA.png\"";
        
//        processBuilder.methodA(oneLongString_ProcessBuilder);
        runtimeExec.methodA(oneLongString_RuntimeExec);
        
      } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
      
      // methodB() uses an array containing the command and the options to pass to the command
      try {

        String[] commandAndOptions_ProcessBuilder = {pathToInkscape, " -f \"C:/test.svg\" -D -w 100 -h 100 -e \"C:\\ProcessBuilder-methodB.png\""};
        String[] commandAndOptions_RuntimeExec =    {pathToInkscape, " -f \"C:/test.svg\" -D -w 100 -h 100 -e \"C:\\RuntimeExec-methodB.png\""};
        
        processBuilder.methodB(commandAndOptions_ProcessBuilder);
//        runtimeExec.methodB(commandAndOptions_RuntimeExec);
        
      } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }
}

RuntimeExecCaller.java

package conversion;

import java.io.IOException;

public class RuntimeExecCaller {
    Process process;
    
    // use one string
    public void methodA(String oneLongString) throws IOException {
      process = Runtime.getRuntime().exec(oneLongString);
    }
    
    // use the array
    public void methodB(String[] commandAndOptions) throws IOException {
      process = Runtime.getRuntime().exec(commandAndOptions);
    }
}

ProcessBuilderCaller.java

package conversion;

import java.io.IOException;

public class ProcessBuilderCaller {
    Process process;
    
    // use one string
    public void methodA(String oneLongString) throws IOException {
      process = new ProcessBuilder(oneLongString).start();
    }
    
    // use the array
    public void methodB(String[] commandAndOptions) throws IOException {
      process = new ProcessBuilder(commandAndOptions).start();
    }
}

结果

两个 methodA(String) 调用都有效,但是当调用 methodB(String[]) 时,Inkscape 正在启动并且参数传递不正确。 methodB(String[]) 执行后,我会为每个说法得到一个 Inkscape 错误对话框

加载请求文件失败 -f C:/test.svg -D -w 100 -h 100 -e C:\RuntimeExec-methodB.png

加载请求文件失败 -f C:/test.svg -D -w 100 -h 100 -e C:\ProcessBuilder-methodB.png

当我单击对话框上的关闭时,Inkscape 会弹出一个新的空白文档。所以,我想我有几个问题:

Runtime.getRuntime().exec(String) 和 Runtime.getRuntime().exec(String[]) 有什么区别?

JavaDoc 说 Runtime.exec(String) 调用 Runtime.exec(command, null) (即 Runtime.exec(String cmd, String[] envp)) 依次调用 Runtime.exec(cmdarray, envp) (即 Runtime.exec(String[] cmdarray, String[] envp))。那么,如果 Runtime.getRuntime().exec(String) 无论如何都在调用 Runtime.exec(String[]),为什么我在使用不同的方法时会得到不同的结果?

Java 根据调用的方法不同地设置环境的幕后发生了什么?

【问题讨论】:

    标签: java external-process runtime.exec processbuilder inkscape


    【解决方案1】:

    我怀疑您的问题源于您指定参数列表的方式。本质上,您将“-f C:/test.svg -D -w 100 -h 100 -e C:\RuntimeExec-methodB.png”作为一个单独的参数传递给 Inkscape。

    您需要做的是单独传递参数,如下所示:

    String[] commandAndOptions_ProcessBuilder = {pathToInkscape, "-f", "C:\\est.svg", "-D", "-w", "100", "-h", "100", "-e", "C:\\ProcessBuilder-methodB.png"};
    String[] commandAndOptions_RuntimeExec = {pathToInkscape, "-f", "C:\\test.svg", "-D", "-w", "100", "-h", "100", "-e","C:\\RuntimeExec-methodB.png"};
    

    粗略地说,当您使用Runtime.exec(String) 时,您传入的值将由shell 评估,从而解析出参数列表。当您使用Runtime.exec(String[]) 时,您提供的是参数列表,因此不需要处理。这样做的好处是您不必转义 shell 的特殊值,因为它不会评估参数。

    【讨论】:

    • 我很确定 Java 会处理 ProcessBuilderRuntime.exec() 中的参数拆分,但其他方面是正确的。
    • @Jonathan,快速查看运行时表明您是正确的 - StringTokenizer 用于分解空格上的字符串。这意味着如果您的可执行文件路径中有空格,则需要使用 Runtime.exec(String[])。
    猜你喜欢
    • 2011-10-14
    • 1970-01-01
    • 1970-01-01
    • 2019-01-17
    • 2016-01-05
    • 1970-01-01
    • 2012-02-05
    • 1970-01-01
    相关资源
    最近更新 更多