ProcessBuilder与Runtime.exec()

bla*_*rno 9 java external-process runtime.exec inkscape processbuilder

我正在尝试使用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();
      }
    }
}
Run Code Online (Sandbox Code Playgroud)

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

结果

这两个了methodA(字符串)调用的工作,但是当的methodB(字符串[]),被称为正在启动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)(即运行时) .exec(String [] cmdarray,String [] envp)).所以,如果Runtime.getRuntime().exec(String)正在调用Runtime.exec(String []),为什么我在使用不同的方法时会得到不同的结果?

幕后发生的事情是Java根据调用的方法设置不同的环境吗?

use*_*kci 12

我怀疑你的问题源于你指定你的参数列表的方式.从本质上讲,你将" -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"};
Run Code Online (Sandbox Code Playgroud)

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

  • @Jonathan,快速浏览一下Runtime就可以看出你是对的 - StringTokenizer用于在空格上分解字符串.这意味着如果您的可执行文件路径中有空格,则需要使用Runtime.exec(String []). (2认同)