web-dev-qa-db-fra.com

Exécuter une autre application à partir de Java

Je dois exécuter un fichier de commandes qui exécute une autre application Java . Je ne me soucie pas de savoir s'il s'exécute correctement ou non, et je n'ai pas à capturer d'erreur.

Est-il possible de faire cela avec ProcessBuilder ? Quelles sont les conséquences si je ne capture pas les erreurs?

Cependant, mon exigence est simplement d'exécuter une autre application Java.

17
user234194

L'approche Runtime.getRuntime().exec() est assez gênante, comme vous le découvrirez bientôt.

Jetez un coup d’œil au projet Apache Commons Exec . Cela résume de nombreux problèmes courants liés à l’utilisation des API Runtime.getRuntime().exec() et ProcessBuilder.

C'est aussi simple que:

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

Oui, il est possible d'utiliser ProcessBuilder.

Exemple de ProcessBuilder:

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

Vérifiez ces exemples:

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

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

25
YoK

Vous pouvez exécuter une instruction batch ou toute autre application à l'aide de

Runtime.getRuntime().exec(cmd);
  • cmd est le chemin de la commande ou de l'application.

De plus, vous pouvez attendre l’exécution et obtenir le code de retour (pour vérifier s’il est exécuté correctement) avec ce code:

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

Vous avez ici une explication complète des différents types d’appels http://www.rgagnon.com/javadetails/Java-0014.html

4
Dubas

Voici un exemple d'utilisation de ProcessBuilder pour exécuter votre application distante. Puisque vous ne vous souciez pas des entrées/sorties et/ou des erreurs, vous pouvez procéder comme suit:

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

la méthode waitFor() attendra la fin du processus avant de continuer. Cette méthode renvoie le code d'erreur du processus mais, comme vous ne vous en souciez pas, je ne l'ai pas mis dans l'exemple.

4
cmevoli

Je suppose que vous savez comment exécuter la commande à l'aide de la variable ProcessBuilder.

L'exécution d'une commande à partir de Java doit toujours lire les flux stdout et stderr du processus. Sinon, il peut arriver que la mémoire tampon soit saturée et que le processus ne puisse pas continuer car l'écriture des blocs stdout ou stderr.

4
Mot

Je sais que c'est un fil plus ancien, mais je pense que cela pourrait valoir la peine de mettre mon implémentation car j'ai trouvé que ce fil essayait de faire la même chose que OP, sauf avec un accès de niveau racine, mais je n'ai pas vraiment trouvé de solution Je cherchais. La méthode ci-dessous crée un shell statique de niveau racine utilisé uniquement pour l'exécution de commandes, indépendamment du contrôle des erreurs ou même si la commande a été exécutée avec succès. 

J'utilise une application de lampe de poche Android que j'ai créée qui permet de régler le voyant à un niveau de luminosité différent. En supprimant toute vérification d'erreur et autres défauts, je peux faire passer la LED à un niveau de luminosité spécifié en aussi peu que 3ms, ce qui ouvre la porte aux LightTones (sonneries avec lumière). Plus de détails sur l'application elle-même peuvent être trouvés ici: http://forum.xda-developers.com/showthread.php?t=2659842

Ci-dessous la classe dans son intégralité. 

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

Ensuite, n'importe où dans mon application pour exécuter une commande, par exemple pour changer la luminosité de la LED, j'appelle simplement:

Shell.exec("echo " + bt.getLevel() + " > "+ flashfile);
2
Derek Ziemba

Le code de fragment ci-dessous est écrit pour compiler et exécuter un programme Java externe à l'aide de ProcessBuilder, de la même manière que nous pouvons exécuter tout programme externe. Assurez-vous que Java_HOME doit être défini dans l'environnement du système d'exploitation. voir plus

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

}

2
Ajay

J'ai pu constater qu'il existe une meilleure bibliothèque que la bibliothèque exec d'Apache commons . Vous pouvez exécuter votre travail à l'aide de Java Secure Shell (JSch).

J'ai eu le même problème. J'ai utilisé JSch pour résoudre ce problème. Apache commons a eu quelques problèmes en exécutant des commandes sur un serveur différent. De plus, JSch m'a donné des résultats et des erreurs InputStreams. Je l'ai trouvé plus élégant. Vous trouverez un exemple de solution ici: 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: Afin de trouver votre processus (s'il s'agit d'un processus de longue durée) en cours d'exécution sous Unix, utilisez le ps -aux | grep Java. L'identifiant du processus doit être indiqué avec la commande unix que vous exécutez.

1
Tammy

Si vous ne vous souciez pas de la valeur de retour, vous pouvez simplement utiliser Runtime.getRuntime().exec("path.to.your.batch.file");

1
James B

Vous pouvez simplement utiliser Runtime.exec ()

0
Gopi