java ProcessBuilder 与 Runtime.exec()

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3997127/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 04:18:12  来源:igfitidea点击:

ProcessBuilder vs Runtime.exec()

javaexternal-processruntime.execprocessbuilderinkscape

提问by blastthisinferno

I'm trying to create a frontend app in Java to handle batch SVG conversions using Inkscape's command line feature. I'm taking and updating the code from https://sourceforge.net/projects/conversionsvg/. The way the original developer handled calling Inkscape by Runtime.getRuntime().exec(String). The issue I'm running into is some inconsistencies between using methodA and methodB. I created a simple java test project to demonstrate the different actions being performed.

我正在尝试在 Java 中创建一个前端应用程序,以使用 Inkscape 的命令行功能处理批量 SVG 转换。我正在从https://sourceforge.net/projects/conversionsvg/获取和更新代码。原始开发人员通过Runtime.getRuntime().exec(String)处理调用 Inkscape 的方式。我遇到的问题是使用方法 A 和方法 B 之间存在一些不一致。我创建了一个简单的 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

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();
    }
}

Result

结果

Both methodA(String)calls work, but when methodB(String[])is called Inkscape is being started and the arguments are being passed incorrectly. After methodB(String[])executes I get an Inkscape error dialog for each saying

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

Failed to load the requested file -f C:/test.svg -D -w 100 -h 100 -e C:\RuntimeExec-methodB.png

Failed to load the requested file -f C:/test.svg -D -w 100 -h 100 -e C:\ProcessBuilder-methodB.png

无法加载请求的文件 -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

and when I click Close on the dialog, Inkscape pops up with a new blank document. So, I guess I have a few questions:

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

What is the difference between Runtime.getRuntime().exec(String) and Runtime.getRuntime().exec(String[])?

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

JavaDoc says that Runtime.exec(String)calls Runtime.exec(command, null)(which is Runtime.exec(String cmd, String[] envp)) which in turn calls Runtime.exec(cmdarray, envp)(which is Runtime.exec(String[] cmdarray, String[] envp)). So, if Runtime.getRuntime().exec(String)is calling Runtime.exec(String[])anyways, why am I getting different results when using different methods?

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[]),为什么在使用不同的方法时会得到不同的结果?

Is something happening behind the scenes where Java sets up the environment differently depending on which method is called?

是否在幕后发生了一些事情,其中​​ Java 根据调用的方法来设置不同的环境?

回答by userkci

I suspect your problem stems from the way you're specifying your argument list. Essentially, you're passing "-f C:/test.svg -D -w 100 -h 100 -e C:\RuntimeExec-methodB.png" as one single argumentto Inkscape.

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

What you need to do is pass the arguments individually, like so:

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

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"};

Roughly speaking, when you use Runtime.exec(String), the value you pass in gets evaluated by the shell, which parses out the argument list. When you use Runtime.exec(String[]), you're providing the argument list, so it doesn't need processing. A benefit of doing this is that you don't have to escape values special to the shell, as the arguments will not be evaluated by it.

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