Difference between ProcessBuilder and Runtime.exec()
The various overloads of Runtime.getRuntime().exec(...)
take either an array of strings or a single string. The single-string overloads of exec()
will tokenise the string into an array of arguments, before passing the string array onto one of the exec()
overloads that takes a string array. The ProcessBuilder
constructors, on the other hand, only take a varargs array of strings or a List
of strings, where each string in the array or list is assumed to be an individual argument. Either way, the arguments obtained are then joined up into a string that is passed to the OS to execute.
So, for example, on Windows,
Runtime.getRuntime().exec("C:\DoStuff.exe -arg1 -arg2");
will run a DoStuff.exe
program with the two given arguments. In this case, the command-line gets tokenised and put back together. However,
ProcessBuilder b = new ProcessBuilder("C:\DoStuff.exe -arg1 -arg2");
will fail, unless there happens to be a program whose name is DoStuff.exe -arg1 -arg2
in C:\
. This is because there's no tokenisation: the command to run is assumed to have already been tokenised. Instead, you should use
ProcessBuilder b = new ProcessBuilder("C:\DoStuff.exe", "-arg1", "-arg2");
or alternatively
List<String> params = java.util.Arrays.asList("C:\DoStuff.exe", "-arg1", "-arg2");
ProcessBuilder b = new ProcessBuilder(params);
ProcessBuilder vs Runtime.getRuntime().exec different behavior
I found the difference:
By default Runtime.getRuntime().exec
will tokenize the input, in the case of ProcessBuilder
it will execute the command as it is (i.e: won't tokenize)
This is why the Runtime
version can work properly, it will separate the command as:["buildr", "run"]
and in the other hand ProcessBuilder
will run as: ["buildr run"]
.
The solution: Tokenize before using ProcessBuilder
e.g:
String[] cmdAsTokens = command.split(" ");
Process process = new ProcessBuilder(cmdAsTokens)
.directory(folder)
.redirectErrorStream(true)
.start();
ProcessBuilder vs Runtime.exec()
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.
Why should avoid using Runtime.exec() in java?
Unless you're stuck on an ancient JVM, java.lang.ProcessBuilder
makes it much easier to specify a process, set up its environment, spawn it, and handle its file descriptors.
This class is used to create operating system processes.
Each
ProcessBuilder
instance manages a collection of process attributes. Thestart()
method creates a newProcess
instance with those attributes. Thestart()
method can be invoked repeatedly from the same instance to create new subprocesses with identical or related attributes....
Starting a new process which uses the default working directory and environment is easy:
Process p = new ProcessBuilder("myCommand", "myArg").start();
Here is an example that starts a process with a modified working directory and environment:
ProcessBuilder pb = new ProcessBuilder("myCommand", "myArg1", "myArg2");
Map<String, String> env = pb.environment();
env.put("VAR1", "myValue");
env.remove("OTHERVAR");
env.put("VAR2", env.get("VAR1") + "suffix");
pb.directory(new File("myDir"));
Process p = pb.start();
ProcessBuilder gives a No such file or directory on Mac while Runtime().exec() works fine
You need to specify the arguments as separate Strings
:
new ProcessBuilder("cmd", "arg1", "arg2", ...);
The constructor accepts String
, varargs
, and List<String>
.
See ProcessBuilder documentation.
Related Topics
How to Get the Current Date/Time in Java
How to Implement Constants in Java
Does Use of Final Keyword in Java Improve the Performance
How to Add Custom Method to Spring Data JPA
How to Iterate Through the Files in a Directory and It's Sub-Directories in Java
Java Array, Finding Duplicates
What Is the Garbage Collector in Java
How to Set the Classpath in Netbeans
How to Make an Image Move While Listening to a Keypress in Java
What Is @Modelattribute in Spring MVC
Initialising a Multidimensional Array in Java
Convert Date/Time for Given Timezone - Java
Why Does the Tostring Method in Java Not Seem to Work for an Array
Dynamically Add Components to a Jdialog