2010-10-22 55 views
9

我想在Java中創建一個前端應用程序來處理批量SVG轉換使用Inkscape的命令行功能。我正在更新https://sourceforge.net/projects/conversionsvg/的代碼。原始開發者通過Runtime.getRuntime()。exec(String)處理調用Inkscape的方式。我遇到的問題是使用methodA和methodB之間的一些不一致。我創建了一個簡單的java測試項目來演示正在執行的不同操作。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(); 
    } 
} 

結果

兩個了methodA(字符串)呼叫無效,但是當的methodB(字符串[])被稱爲正在啓動Inkscape中和參數被錯誤地傳遞。 的methodB(字符串[])執行後,我得到一個Inkscape的錯誤對話框對每個說法

無法加載請求的文件-f C:/test.svg -D -w 100 -h 100 -eÇ :\ RuntimeExec-methodB.png

無法加載所請求的文件-f C:/test.svg -D -w 100 -h 100 -e C:\的ProcessBuilder-methodB.png

和當我點擊對話框上的關閉時,Inkscape彈出一個新的空白文檔。所以,我想我有幾個問題:

Runtime.getRuntime()。exec(String)和Runtime.getRuntime()。exec(String [])有什麼區別?

JavaDoc的說,的Runtime.exec(字符串)呼叫的Runtime.exec(命令,NULL)(其爲的Runtime.exec(字符串CMD,字符串[] envp)),其在打電話Runtime.exec(cmdarray,envp)(即Runtime.exec(String [] cmdarray,String [] envp))。因此,如果Runtime.getRuntime().exec(String)正在調用Runtime.exec(String [])反正,爲什麼我在使用不同的方法時得到不同的結果?

發生在幕後的事情是Java根據調用的方法設置不同的環境嗎?

回答

12

我懷疑你的問題源於你指定參數列表的方式。實質上,您將「-f C:/test.svg -D -w 100 -h 100 -e C:\RuntimeExec-methodB.png」作爲一個參數傳遞給Inkscape。

你需要做的就是傳遞參數單獨,就像這樣:

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

粗略地說,當你使用Runtime.exec(String),你傳遞的價值得到由殼評估,其中分析了參數列表。當你使用Runtime.exec(String[])時,你提供了參數列表,所以它不需要處理。這樣做的好處是你不必爲shell特殊的值轉義,因爲參數不會被它評估。

+0

我很確定Java處理分裂'ProcessBuilder'或'Runtime.exec()'中的參數,但在其他方面是正確的。 – Jonathan 2010-10-22 14:16:11

+2

@Jonathan,快速瀏覽一下Runtime表明你是正確的--StringTokenizer用來分割空白字符串。這意味着如果您的可執行文件路徑中有空格,則需要使用Runtime.exec(String [])。 – userkci 2010-10-22 15:28:22