2010-10-22 15 views
9

Estoy tratando de crear una aplicación frontend en Java para manejar las conversiones SVG por lotes utilizando la función de línea de comando de Inkscape. Estoy tomando y actualizando el código de https://sourceforge.net/projects/conversionsvg/. La forma en que el desarrollador original manejó llamar a Inkscape por Runtime.getRuntime(). Exec (String). El problema al que me estoy enfrentando es algunas inconsistencias entre usar methodA y methodB. Creé un proyecto simple de prueba de Java para demostrar las diferentes acciones que se realizan.ProcessBuilder vs Runtime.exec()

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

de Resultados

Tanto MethodA (String) llamadas de trabajo, pero cuando methodB (String []) se llama se va a iniciar Inkscape y los argumentos se pasan de forma incorrecta. Después methodB (String []) ejecuta consigo un diálogo de error Inkscape para decir cada uno

No se pudo cargar el archivo solicitado -f C: /test.svg -D -w 100 -h 100 -e C : \ RuntimeExec-methodB.png

No se ha podido cargar el archivo solicitado -f C: /test.svg -D -w 100 -h 100 -e C: \ ProcessBuilder-methodB.png

y cuando hago clic en Cerrar en el diálogo, aparece Inkscape con un nuevo documento en blanco. Entonces, supongo que tengo algunas preguntas:

¿Cuál es la diferencia entre Runtime.getRuntime(). Exec (String) y Runtime.getRuntime(). Exec (String [])?

JavaDoc dice que Runtime.exec (cadena) llamadas Runtime.exec (mando, null) (que es Runtime.exec (CMD String, String [] envp)) que a su turn llamadas Runtime.exec (cmdarray, envp) (que es Runtime.exec (String [] cmdarray, String [] envp)). Entonces, si Runtime.getRuntime(). Exec (String) llama a Runtime.exec (String []) de todos modos, ¿por qué obtengo resultados diferentes cuando uso diferentes métodos?

¿Hay algo detrás de escena en el que Java configura el entorno de forma diferente según el método que se llame?

Respuesta

12

Sospecho que su problema se debe a la forma en que especifica su lista de argumentos. Esencialmente, está pasando "-f C:/test.svg -D -w 100 -h 100 -e C:\RuntimeExec-methodB.png" como un solo argumento a Inkscape.

Lo que hay que hacer es pasar los argumentos individual, así:

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

En términos generales, cuando se utiliza Runtime.exec(String), el valor que se pasa en se evalúa por la cáscara, que analiza la lista de argumentos. Cuando usa Runtime.exec(String[]), proporciona la lista de argumentos, por lo que no necesita procesamiento. Una ventaja de hacer esto es que no tiene que escapar de valores especiales para el shell, ya que los argumentos no serán evaluados por él.

+0

Estoy bastante seguro de que Java maneja dividir los argumentos en 'ProcessBuilder' o' Runtime.exec() ', pero de lo contrario correctos. – Jonathan

+2

@Jonathan, un vistazo rápido a Runtime muestra que está en lo cierto: StringTokenizer se usa para dividir la cadena en espacios en blanco. Lo que significa que si tienes espacios en blanco en la ruta de tu ejecutable, necesitarás usar Runtime.exec (String []). – userkci

Cuestiones relacionadas