2009-09-02 13 views
4

Ich brauche einen "System" -Funktionsaufruf, derselbe wie in Python, Perl, PHP, Ruby, & c. Es wird eine Komponente einer JavaScript-Standardbibliothek namens Narwhal sein, wenn es auf der Rhino-JavaScript-Engine ausgeführt wird, die wiederum auf Java ausgeführt wird.Implementierung des "System" -Befehls in Java

Das Problem ist, dass die Java-Standard-Bibliothek die Fähigkeit, einen Subprozess zu erzeugen, abstrahiert hat, der das stdio des Elternprozesses teilt. Dies bedeutet, dass Sie Interaktivität nicht auf den Subprozess verzögern können.

Mein erster Crack dabei war Pythons subprocess.popen zu implementieren. Dies verwendet drei "pumper" -Threads, um das stdio des übergeordneten Prozesses unabhängig zu kopieren (um Deadlock zu verhindern). Leider gibt uns das zwei Probleme. Erstens wird die Eingabe nicht automatisch geschlossen, wenn der Unterprozess freiwillig beendet wird. Zweitens puffern und strömen die Ströme zum Kindprozess nicht richtig.

Ich suche nach Lösungen, die unseren require ("os"). System() Befehl funktionieren würde, wie man erwarten würde.

Das Projekt ist bei http://narwhaljs.org

Relevante Code:

Antwort

2

Nicht sicher, ob dies ist, was Sie suchen, aber Sie können die C system Funktion durch die JNA library aufrufen:

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

oberflächlicher Tests arbeitete unter Windows, sowieso.

+0

Durch das Hinzufügen des jni.jar konnte dieses Bit JavaScript erfolgreich eingesetzt werden. Vielen Dank! var jna = Pakete.com.sun.jna; var clib = jna.NativeLibrary.getInstance (jna.Platform.isWindows()? "Msvcrt": "c"); var csystem = clib.getFunction ("System"); csystem.invoke (["Echo Hallo, Welt!"]); http://gist.github.com/181225 –

1

Sie müssen den Prozess-Exit-Status getrennt, entweder durch Abfrage der Code Ausgang überwachen oder indem ein separater Thread in der Process.waitFor() Methode wartet.

In Bezug auf die Pufferung und Spülung der Ströme, ich denke nicht, dass es eine einfache Lösung gibt. Es gibt mehrere Java-Klassen, die in verschiedenen Formen puffern (BufferedInputStream, etc). Vielleicht kann einer von ihnen helfen?

+0

@Joachim: Danke für die hinzugefügten Links! – JesperE

1

Wenn ich Sie richtig bin zu verstehen, wollen Sie etwas wie folgt aus:

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

ich dieses Stück Code gefunden: JavaWorld vor einiger Zeit, als ich für eine ähnliche Lösung suchen System zu wickeln, um einige Anrufe exe Dateien.

Mein Code hat sich seitdem etwas weiterentwickelt, aber ich denke, das ist ein gutes Beispiel.

+0

+1 für den gleichzeitigen Verbrauch –

0

Es ist wirklich wichtig, die Prozessstandardausgabe und Fehler gleichzeitig zu konsumieren. Siehe Carlos Tasadas Beispielcode an anderer Stelle hier.

Wenn Sie dies nicht tun, kann Ihr Code abhängig von der Ausgabe Ihres erstellten Prozesses funktionieren (oder auch nicht). Wenn sich diese Ausgabe ändert (wenn Ihr generierter Prozess beispielsweise einen Fehler feststellt), wird Ihr Prozess ohne die gleichzeitige Verwendung blockiert. Die meisten Probleme, die ich im Zusammenhang mit SO bezüglich Process.exec() sehe, sind blockierend.