2010-08-12 14 views
14

Potrzebuję wykonać plik wsadowy, który wykonuje inną aplikację Java. Nie obchodzi mnie, czy to się uda, czy nie i nie muszę przechwytywać żadnych błędów.Wykonywanie innej aplikacji z Java

Czy można to zrobić z ProcessBuilder? Jakie są konsekwencje, jeśli nie przechwytuję błędów?

Jednak moim wymaganiem jest wykonanie innej aplikacji Java.

Odpowiedz

4

Zakładam, że wiesz, jak wykonać polecenie przy użyciu ProcessBuilder.

Wykonanie polecenia z Javy zawsze powinno odczytywać strumienie standardowe i stderr z procesu. W przeciwnym razie może się zdarzyć, że bufor jest pełny i proces nie może być kontynuowany, ponieważ zapisuje swoje standardowe bloki lub stderr.

+0

Czy istnieje sposób, aby po prostu uruchomić inną aplikację i zignorować strumienie standardowe i stderr z procesu. – user234194

+0

Może utworzysz plik 'bat', który przekierowuje wyjście wykonanego polecenia do" dev-null ". – Mot

1

Jeśli nie dbam o wartości zwracanej można po prostu użyć Runtime.getRuntime().exec("path.to.your.batch.file");

+0

co ze strumieniami stdout i stderr z procesu zapełniania. – user234194

+0

Bez wiedzy o tym, co chcesz uruchomić, trudno powiedzieć. Widziałem programy takie jak BCP programu SQL Server, które nie zgłaszały błędów poprawnie po uruchomieniu i pytaniu o stdout i strumienie stderr, więc to zależy od twojego procesu potomnego. Jeśli nie ma żadnych danych wyjściowych, to nie martw się o to, stdout i stderr będą śmieciami zebranymi wraz z obiektem 'Process' po zakończeniu procesu. –

+0

Mam proste pytanie, co jeśli tak szybko wykonać inną aplikację java, nie mogę zrobić process.destroy. Czy to nie pomoże, że stdout/err stanie się pełny, czy też mówię o rzeczy total diff. Ponieważ po uruchomieniu innej aplikacji mogę zamknąć aplikację. – user234194

29

Podejście Runtime.getRuntime().exec() jest bardzo kłopotliwe, a dowiecie się wkrótce.

Spójrz na projekt Apache Commons Exec. Wyjaśnia on wiele typowych problemów związanych z korzystaniem z interfejsu API Runtime.getRuntime().exec() i .

Jest to tak proste, jak:

String line = "myCommand.exe"; 
CommandLine commandLine = CommandLine.parse(line); 
DefaultExecutor executor = new DefaultExecutor(); 
executor.setExitValue(1); 
int exitValue = executor.execute(commandLine); 
+1

ta odpowiedź uratowała moje życie. Dzięki – Valath

4

Można wykonać dyspozycję partii, ani żadnej innej aplikacji przy użyciu

Runtime.getRuntime().exec(cmd); 
  • cmd jest polecenie lub Te ścieżki aplikacji.

także yo może czekać na wykonanie i uzyskanie kodu powrotu (w celu sprawdzenia, czy jego wykonany poprawnie) z tym kodem:

Process p = Runtime.getRuntime().exec(cmd); 
    p.waitFor(); 
    int exitVal = p.exitValue(); 

Masz pełne wyjaśnienie różnych rodzajów połączeń tutaj http://www.rgagnon.com/javadetails/java-0014.html

+4

Process.waitFor() faktycznie zwraca kod zakończenia procesu, więc możesz połączyć ostatnie dwie linie z "int.exitVal = p.waitFor();" –

22

Tak jest możliwe za pomocą ProcessBuilder.

ProcessBuilder przykład:

import java.io.*; 
import java.util.*; 

public class CmdProcessBuilder { 
    public static void main(String args[]) 
    throws InterruptedException,IOException 
    { 
    List<String> command = new ArrayList<String>(); 
    command.add(args[0]); 


    ProcessBuilder builder = new ProcessBuilder(command); 
    Map<String, String> environ = builder.environment(); 

    final Process process = builder.start(); 
    InputStream is = process.getInputStream(); 
    InputStreamReader isr = new InputStreamReader(is); 
    BufferedReader br = new BufferedReader(isr); 
    String line; 
    while ((line = br.readLine()) != null) { 
     System.out.println(line); 
    } 
    System.out.println("Program terminated!"); 
    } 
} 

Sprawdź te przykłady:

http://www.rgagnon.com/javadetails/java-0014.html

http://www.java-tips.org/java-se-tips/java.util/from-runtime.exec-to-processbuilder.html

+0

Wyjątek w wątku "główny" java.lang.ArrayIndexOutOfBoundsException: 0 \t w RunClByJava.main (RunClByJava.java:94) –

4

Oto przykład jak używać ProcessBuilder wykonać swoją aplikację zdalną.Ponieważ nie dbają o wejście/wyjście i/lub błędów, można to zrobić w następujący sposób:

List<String> args = new ArrayList<String>(); 
args.add ("script.bat"); // command name 
args.add ("-option"); // optional args added as separate list items 
ProcessBuilder pb = new ProcessBuilder (args); 
Process p = pb.start(); 
p.waitFor(); 

metoda waitFor() będzie czekać, aż proces się skończył przed kontynuowaniem. Ta metoda zwraca kod błędu procesu, ale ponieważ nie dbasz o to, nie wstawiłem go do przykładu.

2

Wiem, że to starsza nitka, ale sądzę, że warto byłoby zastosować moją implementację, ponieważ znalazłem ten wątek próbujący zrobić to samo co OP, z wyjątkiem dostępu do poziomu root, ale nie naprawdę znajduję rozwiązanie, którego szukałem. Poniższa metoda tworzy statyczną powłokę poziomu root, która służy tylko do wykonywania poleceń bez sprawdzania błędów, a nawet jeśli polecenie zostało wykonane pomyślnie.

Używam tej aplikacji na Androida, którą stworzyłem, która pozwala ustawić diodę LED na różnym poziomie jasności. Po usunięciu wszystkich błędów i innych fluffów mogę sprawić, że dioda LED przełączy się na określony poziom jasności w zaledwie 3 ms, co otworzy drzwi do LightTones (RingTones with light). Więcej szczegółów na temat samej aplikacji można znaleźć tutaj: http://forum.xda-developers.com/showthread.php?t=2659842

Poniżej znajduje się klasa w całości.

public class Shell { 
    private static Shell rootShell = null; 
    private final Process proc; 
    private final OutputStreamWriter writer; 

    private Shell(String cmd) throws IOException { 
     this.proc = new ProcessBuilder(cmd).redirectErrorStream(true).start(); 
     this.writer = new OutputStreamWriter(this.proc.getOutputStream(), "UTF-8"); 
    } 

    public void cmd(String command) { 
     try { 
      writer.write(command+'\n'); 
      writer.flush(); 
     } catch (IOException e) { } 
    } 

    public void close() { 
     try { 
      if (writer != null) { writer.close(); 
       if(proc != null) { proc.destroy(); } 
      } 
     } catch (IOException ignore) {} 
    } 

    public static void exec(String command) { Shell.get().cmd(command); } 

    public static Shell get() { 
     if (Shell.rootShell == null) { 
      while (Shell.rootShell == null) { 
       try { Shell.rootShell = new Shell("su"); //Open with Root Privileges 
       } catch (IOException e) { } 
      } 
     } 
     return Shell.rootShell; 
    } 
} 

Następnie gdziekolwiek w mojej aplikacji do uruchomienia polecenia, na przykład zmieniając jasność LED, po prostu zadzwoń:

Shell.exec("echo " + bt.getLevel() + " > "+ flashfile); 
1

Poniżej fragment kodu jest napisane, aby skompilować i uruchomić zewnętrznego programu Java z wykorzystaniem ProcessBuilder, w ten sam sposób możemy uruchomić dowolny program zewnętrzny. Upewnij się, że JAVA_HOME musi być ustawiony w środowisku systemu operacyjnego. zobacz more

package com.itexpert.exam; 

import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.InputStreamReader; 

public class JavaProcessBuilder { 
/** 
* Provide absolute JAVA file path 
*/ 
private static final String JAVA_FILE_LOCATION = "D:\\Test.java"; 

public static void main(String args[]) throws IOException{ 
    String command[] = {"javac",JAVA_FILE_LOCATION}; 
    ProcessBuilder processBuilder = new ProcessBuilder(command); 

    Process process = processBuilder.start(); 
    /** 
    * Check if any errors or compilation errors encounter then print on Console. 
    */ 

    if(process.getErrorStream().read() != -1){ 
     print("Compilation Errors",process.getErrorStream()); 
    } 
    /** 
    * Check if javac process execute successfully or Not 
    * 0 - successful 
    */ 
    if(process.exitValue() == 0){ 
     process = new ProcessBuilder(new String[]{"java","-cp","d:\\","Test"}).start(); 
     /** Check if RuntimeException or Errors encounter during execution then print errors on console 
     * Otherwise print Output 
     */ 
     if(process.getErrorStream().read() != -1){ 
      print("Errors ",process.getErrorStream()); 
     } 
     else{ 
      print("Output ",process.getInputStream()); 
     } 

    } 
} 

private static void print(String status,InputStream input) throws IOException{ 
    BufferedReader in = new BufferedReader(new InputStreamReader(input)); 
    System.out.println("************* "+status+"***********************"); 
    String line = null; 
    while((line = in.readLine()) != null){ 
     System.out.println(line); 
    } 
    in.close(); 
} 

}

1

mogłem zobaczyć, że jest lepiej niż biblioteki commons apache Exec bibliotecznych. Możesz wykonać swoją pracę za pomocą Java Secure Shell (JSch).

Miałem ten sam problem. Użyłem JSch do rozwiązania tego problemu. Apache commons miał pewne problemy z uruchomieniem komend na innym serwerze. Plus JSch dał mi wynik i błędy InputStreams. Znalazłem to bardziej elegancko. Roztwór próbki można znaleźć tutaj: http://wiki.jsch.org/index.php?Manual%2FExamples%2FJschExecExample

import java.io.InputStream; 
    import java.io.BufferedReader; 
    import java.io.InputStreamReader; 

    import org.apache.commons.exec.*; 

    import com.jcraft.*; 
    import com.jcraft.jsch.JSch; 
    import com.jcraft.jsch.Session; 
    import com.jcraft.jsch.ChannelExec; 

    import java.util.Arrays; 
    import java.util.List; 
    import java.util.ArrayList; 
    import java.util.HashMap; 


    public class exec_linux_cmd { 
     public HashMap<String,List<String>> exec_cmd (
       String USERNAME, 
       String PASSWORD, 
       String host, 
       int port, 
       String cmd) 
     { 
      List<String> result = new ArrayList<String>(); 
      List<String> errors = new ArrayList<String>(); 
      HashMap<String,List<String>> result_map = new HashMap<String,List<String>>(); 
     //String line = "echo `eval hostname`"; 
      try{ 
      JSch jsch = new JSch(); 
      /* 
      * Open a new session, with your username, host and port 
      * Set the password and call connect. 
      * session.connect() opens a new connection to remote SSH server. 
      * Once the connection is established, you can initiate a new channel. 
      * this channel is needed to connect and remotely execute the program 
      */ 

      Session session = jsch.getSession(USERNAME, host, port); 
      session.setConfig("StrictHostKeyChecking", "no"); 
      session.setPassword(PASSWORD); 
      session.connect(); 

      //create the excution channel over the session 
      ChannelExec channelExec = (ChannelExec)session.openChannel("exec"); 

      // Gets an InputStream for this channel. All data arriving in as messages from the remote side can be read from this stream. 
      InputStream in = channelExec.getInputStream(); 
      InputStream err = channelExec.getErrStream(); 

      // Set the command that you want to execute 
      // In our case its the remote shell script 

      channelExec.setCommand(cmd); 

      //Execute the command 
      channelExec.connect(); 

      // read the results stream 
      BufferedReader reader = new BufferedReader(new InputStreamReader(in)); 
      // read the errors stream. This will be null if no error occured 
      BufferedReader err_reader = new BufferedReader(new InputStreamReader(err)); 
      String line; 

      //Read each line from the buffered reader and add it to result list 
      // You can also simple print the result here 

      while ((line = reader.readLine()) != null) 
      { 
       result.add(line); 
      } 

      while ((line = err_reader.readLine()) != null) 
      { 
       errors.add(line); 
      } 

      //retrieve the exit status of the remote command corresponding to this channel 
      int exitStatus = channelExec.getExitStatus(); 
      System.out.println(exitStatus); 

      //Safely disconnect channel and disconnect session. If not done then it may cause resource leak 
      channelExec.disconnect(); 
      session.disconnect(); 
      System.out.println(exitStatus); 
      result_map.put("result", result); 
      result_map.put("error", errors); 

      if(exitStatus < 0){ 
       System.out.println("Done--> " + exitStatus); 
       System.out.println(Arrays.asList(result_map)); 
       //return errors; 
      } 
      else if(exitStatus > 0){ 
       System.out.println("Done -->" + exitStatus); 
       System.out.println(Arrays.asList(result_map)); 
       //return errors; 
      } 
      else{ 
       System.out.println("Done!"); 
       System.out.println(Arrays.asList(result_map)); 
       //return result; 
      } 

      } 
      catch (Exception e) 
      { 
       System.out.print(e); 
      } 

      return result_map; 
     } 



     //CommandLine commandLine = CommandLine.parse(cmd); 
     //DefaultExecutor executor = new DefaultExecutor(); 
     //executor.setExitValue(1); 
     //int exitValue = executor.execute(commandLine); 

      public static void main(String[] args) 
      { 
       //String line = args[0]; 
       final String USERNAME ="abc"; // username for remote host 
       final String PASSWORD ="abc"; // password of the remote host 
       final String host = "3.98.22.10"; // remote host address 
       final int port=22; // remote host port 
       HashMap<String,List<String>> result = new HashMap<String,List<String>>(); 

       //String cmd = "echo `eval hostname`"; // command to execute on remote host 
       exec_linux_cmd ex = new exec_linux_cmd(); 

       result = ex.exec_cmd(USERNAME, PASSWORD , host, port, cmd); 
       System.out.println("Result ---> " + result.get("result")); 
       System.out.println("Error Msg ---> " +result.get("error")); 
       //System.out.println(Arrays.asList(result)); 

       /* 
       for (int i =0; i < result.get("result").size();i++) 
       { 
         System.out.println(result.get("result").get(i)); 
       } 
       */ 

      } 
    } 

EDIT 1: W celu znalezienia proces (jeśli jej długo uruchomiony jeden) są wykonywane na Uniksie, użyj ps -aux | grep java. Identyfikator procesu powinien znajdować się na liście wraz z wykonywanym poleceniem unix.

Powiązane problemy