Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
335 views
in Technique[技术] by (71.8m points)

java - ProcessBuilder vs Runtime.exec()

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.

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

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

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

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

What is the difference between Runtime.getRuntime().exec(String) and 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?

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

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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 argument to 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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...