9

J'essaie de créer une application frontend en Java pour gérer les conversions SVG par lots en utilisant la fonction de ligne de commande d'Inkscape. Je prends et met à jour le code de https://sourceforge.net/projects/conversionsvg/. La façon dont le développeur d'origine a géré l'appel d'Inkscape par Runtime.getRuntime(). Exec (String). Le problème que je rencontre est quelques incohérences entre l'utilisation de methodA et methodB. J'ai créé un projet de test java simple pour démontrer les différentes actions effectuées.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(); 
    } 
} 

Résultat

deux methodA (String) appels de travail, mais quand methodB (String []) est appelé Inkscape est en cours de démarrage et les arguments sont transmis de façon incorrecte. Après methodB (String []) exécute je reçois un message d'erreur Inkscape pour chaque dire

Impossible de charger le fichier demandé -f C: /test.svg -D -w 100 -h 100 -e C : \ RuntimeExec-methodB.png

Impossible de charger le fichier demandé -f C: /test.svg -D -w 100 -h 100 -e C: \ ProcessBuilder-methodB.png

et Lorsque je clique sur Fermer dans la boîte de dialogue, Inkscape apparaît avec un nouveau document vide. Donc, je suppose que j'ai quelques questions:

Quelle est la différence entre Runtime.getRuntime(). Exec (String) et Runtime.getRuntime(). Exec (String [])?

JavaDoc dit que Runtime.exec (chaîne) appels Runtime.exec (commande, null) (qui est Runtime.exec (String cmd, String [] envp)) qui retourner les appels Runtime.exec (cmdarray, envp) (qui est Runtime.exec (String [] cmdarray, String [] envp)). Donc, si Runtime.getRuntime(). Exec (String) appelle Runtime.exec (String []) de toute façon, pourquoi ai-je des résultats différents lorsque j'utilise différentes méthodes?

Y a-t-il quelque chose derrière les coulisses où Java configure différemment l'environnement en fonction de la méthode appelée?

Répondre

12

Je soupçonne que votre problème provient de la façon dont vous spécifiez votre liste d'arguments. Essentiellement, vous passez "-f C:/test.svg -D -w 100 -h 100 -e C:\RuntimeExec-methodB.png" comme un seul argument à Inkscape.

Ce que vous devez faire est de passer les arguments individuellement, comme ceci:

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

grosso modo, lorsque vous utilisez Runtime.exec(String), la valeur que vous passez obtient évaluée par la coquille, qui parse la liste d'arguments. Lorsque vous utilisez Runtime.exec(String[]), vous fournissez la liste des arguments, elle n'a donc pas besoin d'être traitée. Un avantage de cela est que vous n'avez pas besoin d'échapper des valeurs spéciales pour le shell, car les arguments ne seront pas évalués par lui.

+0

Je suis à peu près sûr que Java gère la séparation des arguments dans 'ProcessBuilder' ou 'Runtime.exec()', mais autrement correct. – Jonathan

+2

@Jonathan, un coup d'œil sur Runtime montre que vous avez raison - StringTokenizer est utilisé pour décomposer la chaîne sur les espaces. Ce qui signifie que si vous avez des espaces dans le chemin de votre exécutable, vous devrez utiliser Runtime.exec (String []). – userkci

Questions connexes