2009-09-02 60 views
4

我需要一個「系統」函數調用,與Python,Perl,PHP,Ruby,&中的那些調用相同。它將成爲稱爲Narwhal的JavaScript標準庫的一個組件,當它在Rhino JavaScript引擎上運行時,它反過來在Java上運行。在Java中實現「system」命令

麻煩的是,Java的標準庫似乎已經抽象出了產生共享父進程的stdio的子進程的能力。這意味着你不能推遲交互到子進程。

我的第一個破解就是實現Python的subprocess.popen。這使用三個「pumper」線程來獨立主動複製父進程的stdio(以防止死鎖)。不幸的是,這給了我們兩個問題。首先,當子過程自動退出時,輸入不會自動關閉。其次,到子進程的流不會緩衝並正確刷新。

我正在尋找能夠使我們的要求(「os」)。system()命令按預期工作的解決方案。

該項目是在http://narwhaljs.org

相關代碼:

回答

2

不知道這是你在找什麼,但你可以通過調用JNA library的C system功能:

public class System { 
    public interface C extends Library { 
    C INSTANCE = (C) Native.loadLibrary(
     (Platform.isWindows() ? "msvcrt" : "c"), C.class); 

    public int system(String format); 
    } 

    public static void main(String[] args) { 
    C.INSTANCE.system("vi"); 
    } 
} 

走馬測試工作在Windows,無論如何。

+0

添加jni.jar,這一點的JavaScript做到了。謝謝! var jna = Packages.com.sun.jna; var clib = jna.NativeLibrary.getInstance(jna.Platform.isWindows()?「msvcrt」:「c」); var csystem = clib.getFunction(「system」); csystem.invoke([「echo Hello,World!」]); http://gist.github.com/181225 – 2009-09-05 00:25:43

1

您需要單獨監控進程退出狀態,通過輪詢退出代碼或者通過在Process.waitFor()方法中等待一個單獨的線程。

關於緩衝和沖刷溪流的問題,我不是有一個簡單的解決方案。有幾個Java類以不同形式緩存(BufferedInputStream等)。也許其中一個可以幫助?

+0

@Joachim:感謝您的補充鏈接! – JesperE 2009-09-03 10:02:54

1

如果我正確理解你,你想這樣的事情:

import java.util.*; 
import java.io.*; 
class StreamGobbler extends Thread 
{ 
    InputStream is; 
    String type; 
    OutputStream os; 

    StreamGobbler(InputStream is, String type) 
    { 
     this(is, type, null); 
    } 
    StreamGobbler(InputStream is, String type, OutputStream redirect) 
    { 
     this.is = is; 
     this.type = type; 
     this.os = redirect; 
    } 

    public void run() 
    { 
     try 
     { 
      PrintWriter pw = null; 
      if (os != null) 
       pw = new PrintWriter(os); 

      InputStreamReader isr = new InputStreamReader(is); 
      BufferedReader br = new BufferedReader(isr); 
      String line=null; 
      while ((line = br.readLine()) != null) 
      { 
       if (pw != null) 
        pw.println(line); 
       System.out.println(type + ">" + line);  
      } 
      if (pw != null) 
       pw.flush(); 
     } catch (IOException ioe) 
      { 
      ioe.printStackTrace(); 
      } 
    } 
} 
public class GoodWinRedirect 
{ 
    public static void main(String args[]) 
    { 
     if (args.length < 1) 
     { 
      System.out.println("USAGE java GoodWinRedirect <outputfile>"); 
      System.exit(1); 
     } 

     try 
     {    
      FileOutputStream fos = new FileOutputStream(args[0]); 
      Runtime rt = Runtime.getRuntime(); 
      Process proc = rt.exec("java jecho 'Hello World'"); 
      // any error message? 
      StreamGobbler errorGobbler = new 
       StreamGobbler(proc.getErrorStream(), "ERROR");    

      // any output? 
      StreamGobbler outputGobbler = new 
       StreamGobbler(proc.getInputStream(), "OUTPUT", fos); 

      // kick them off 
      errorGobbler.start(); 
      outputGobbler.start(); 

      // any error??? 
      int exitVal = proc.waitFor(); 
      System.out.println("ExitValue: " + exitVal); 
      fos.flush(); 
      fos.close();   
     } catch (Throwable t) 
      { 
      t.printStackTrace(); 
      } 
    } 
} 

我發現這段代碼:JavaWorld年前的某個時候,當我在尋找一個類似的解決方案來包裝系統調用一些exe文件。

從那以後,我的代碼已經發展了一些,但我認爲它是一個很好的例子。

+0

+1爲併發消費 – 2009-09-03 10:10:58

0

同時消耗過程標準輸出和錯誤真的很重要。請參閱Carlos Tasada的示例代碼。

如果你不這樣做,你的代碼可能(或不可能)依賴於你衍生的過程的輸出。當輸出發生變化時(如果你的產生的進程遇到錯誤,比方說),那麼沒有併發的消耗,你的進程就會死鎖。我在SO上看到的大多數與Process.exec()相關的問題都與阻塞相關。