IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Java Discussion :

Problème avec Process.getInputStream()


Sujet :

Java

  1. #1
    Membre Expert
    Avatar de yotta
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    Septembre 2006
    Messages
    1 088
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Technicien maintenance
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2006
    Messages : 1 088
    Par défaut Problème avec Process.getInputStream()
    Bonsoir,

    J'aimerai écrire un petit bout de code java pour lancer un programme "cible" externe, et récupérer sa sortie verbeuse standard. En gros, lorsque je lance mon programme "cible" normalement, depuis une fenêtre DOS sous Windows ou depuis un shell Linux, des informations s'affichent dans la fenêtre de commande pendant que le programme fonctionne. J'aimerai pouvoir récupérer dynamiquement ces informations. Donc, j'ai écrits le petit bout de code suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Process processusCible = Runtime.getRuntime().exec("/machin/chose/programme cible");
    BufferedReader lecteur = new BufferedReader(new InputStreamReader(processusCible.getInputStream()));
    while (!lecteur.ready()) Thread.sleep(5);
    while (lecteur.ready()) System.out.println(lecteur.readLine());
    Cela fonctionne, mais pas comme je m'y attendais. Lorsque je lance en ligne de commande mon bout de code Java, ce dernier prend bien le prompt, lance mon programme cible, puis rien......
    Je manipule un peu le logiciel cible, ce qui est sensé lui faire sortir quelques infos dans la fenêtre de commande, mais toujours rien. Je quitte le programme cible et là, tout ce que je pensais voir s'afficher dynamiquement s'affiche d'un seul tenant ?!
    En clair, j'obtiens bien ce que je cherche, mais seulement quand je quitte le programme cible. Ce qui ne m'arrange pas, mon code est sensé réagir lors de la capture de certaines informations, pas lorsque l'on quitte le programme cible...
    Si quelqu'un pouvait m'expliquer pourquoi mon BufferedReader ne reçoit ses informations que lorsque je quitte le programme cible ?

    Un grand merci à tous ceux qui se pencheront sur ce problème, et tous mes meilleurs voeux de fin d'année à vous tous.
    Une technologie n'est récalcitrante que par ce qu'on ne la connait et/ou comprend pas, rarement par ce qu'elle est mal faite.
    Et pour cesser de subir une technologie récalcitrante, n'hésitez surtout pas à visiter les Guides/Faq du site !

    Voici une liste non exhaustive des tutoriels qui me sont le plus familiers :
    Tout sur Java, du débutant au pro : https://java.developpez.com/cours/
    Tout sur les réseaux : https://reseau.developpez.com/cours/
    Tout sur les systèmes d'exploitation : https://systeme.developpez.com/cours/
    Tout sur le matériel : https://hardware.developpez.com/cours/

  2. #2
    Membre Expert
    Avatar de yotta
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    Septembre 2006
    Messages
    1 088
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Technicien maintenance
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2006
    Messages : 1 088
    Par défaut
    Bonjour à vous tous,
    Comme je n'ai pas eu de réponse, je vais préciser certaines choses. En effet, en me relisant, je constate que c'est un peu flou. Donc voilà :
    Machine sur laquelle le programme cible (Blender, un programme de graphisme 3D) se trouve : PC HP dc7800 sous Linux Debian 7.7 64 bits avec openJDK7 intégré à cette distribution + Netbeans 7 intégré à cette distribution.
    Sur cette même machine, j'aimerai faire tourner un programme Java qui récupère la sortie console de Blender.
    D'où l'idée de faire lancer le programme Blender par mon programme Java, puis de récupérer le flux InputStream de l'instance Process qui représente l'application Blender.
    J'ai tenté de faire autrement que de passer par Runtime.exec(...) en utilisant ProcessBuilder, ce qui donne le code suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    ProcessBuilder instance = new ProcessBuilder("/home/thierry/blender272b/blender");
    instance.redirectOutput(Redirect.INHERIT);
    Process processusBlender = instance.start();
    processusBlender.waitFor();
    Ce code fonctionne, mais pas de la même manière selon que je le lance depuis NetBeans, ou en dehors de NetBeans. Depuis NetBeans, il se comporte exactement comme le code précédent, je ne vois apparaître dans la fenêtre Output de NetBeans les informations issues de Blender que lorsque je quitte Blender. Par contre, si je le lance en dehors de NetBeans, "java -jar programmeTest.jar" depuis un shell /bin/sh, les informations issues de Blender s'affichent bien dans ma fenêtre shell pendant que le programme tourne, mais je ne sais pas comment les récupérer. Dans le code précédent, je capture le flux, ici, je me contente de le rediriger vers la sortie standard de la JVM. Mais je ne vois pas comment récupérer ce flux, System.in, System.out, comment faire ?

    Si quelqu'un à une idée, je suis preneur...

    Merci à vous tous.
    Une technologie n'est récalcitrante que par ce qu'on ne la connait et/ou comprend pas, rarement par ce qu'elle est mal faite.
    Et pour cesser de subir une technologie récalcitrante, n'hésitez surtout pas à visiter les Guides/Faq du site !

    Voici une liste non exhaustive des tutoriels qui me sont le plus familiers :
    Tout sur Java, du débutant au pro : https://java.developpez.com/cours/
    Tout sur les réseaux : https://reseau.developpez.com/cours/
    Tout sur les systèmes d'exploitation : https://systeme.developpez.com/cours/
    Tout sur le matériel : https://hardware.developpez.com/cours/

  3. #3
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Par défaut
    Tu pourrais lancer ceci

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    /home/thierry/blender272b/blender >> /tmp/output.txt
    et attacher le fichier généré sur le forum? Ca nous aidera à comprendre comment blender fait sa sortie. A vue de pifomètre, je dirais que blender n'envoie pas \n, du coup tu reçois une seule ligne, quand le programme se termine...
    Il n'est pas impossible non plus que blender aie un comportement différente entre un affichage console et un affichage redirigé vers un programme. Tu pourrais essayer de détecter ça avec ce genre de commande:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    /home/thierry/blender272b/blender | more
    => tu verras bien si tout apparait d'un coup ou progressivement.

  4. #4
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Salut,


    Perso je me méfies du ready() car sa réponse n'est pas forcément super fiable.
    En plus cela ne sert à rien dans ton cas. Au contraire cela pourrait bloquer ton programme pour rien...
    Il est préférable de boucler directement sur readLine().


    Je me doute que blender ne doit pas traiter le flux d'entrée, mais il serait quand même plus propre de le fermer au cas où.
    Plus globalement il vaut mieux fermer les flux inutilisés. Au pire c'est une ligne de code inutile, mais cela permet d'éviter les oublis fâcheux.


    Sinon tu dois traiter le flux stdout ou stderr ? Ou les deux ?
    C'est important car si tu lis le mauvais c'est sûr que cela ne marchera pas.
    Tapes ceci en console pour déterminer où vont les logs :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    /home/thierry/blender272b/blender > blender.stdout 2>blender.stderr


    Par exemple si tu veux traiter le flux stdout uniquement, cela donnerait ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    		Process process = new ProcessBuilder("/home/thierry/blender272b/blender")
    			.start();
    		try {
    			// On ferme le flux STDIN du process (inutile)
    			process.getOutputStream().close();
    			// On ferme le flux STDERR du process (on ignore)
    			process.getErrorStream().close();
     
    			// Et on ferme le flux STDOUT :
    			try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
    				String line;
     
    				while ((line=reader.readLine()) != null) {
    					System.out.println(line);
    				}
    			}
    			// normalement on arrive ici lorsque le programme est terminé
    			process.waitFor();
    		} finally {
    			// garde-fou
    			process.destroy();
    		}
    Si tu veux traiter les deux flux stdout/stderr comme un seul flux, il te suffit de rajouter redirectErrorStream(true) sur le ProcessBuilder.
    Si tu veux traiter les flux stdout et stderr de manière distincte, il faut dupliquer le bloc STDOUT en conséquence, mais dans un thread distinct pour éviter des dead-locks.


    a++

  5. #5
    Membre Expert
    Avatar de yotta
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    Septembre 2006
    Messages
    1 088
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Technicien maintenance
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2006
    Messages : 1 088
    Par défaut
    Merci à vous deux,
    Et désolé pour ce délai, mais il m'est tombé un truc dessus qui m'occupe à 200% ces derniers jours.
    Quoi qu'il en soit, comme demandé, tu trouveras le fichier output.txt ajouté au post, Tchize. Et ta remarque m'a fait réagir. En effet, Blender "pilote" la fenêtre de sortie puisqu'il y envoi les sorties standard des scripts Python qu'il peut exécuter. Peut-être que du coup, ce que je veux faire ne sera pas possible ainsi. Je vais gratter de ce côté.
    Pour ce qui concerne le flux qui m'intéresse, il s'agit simplement du flux stdout.
    Ensuite, d'après tes précisions et ton code, adiGuba, je me demande s'il ne me suffit pas de reprendre le code avec ProcessBuilder et juste avant de le démarrer, lancer un Thread qui se contenterai d'écouter System.in...
    En tout cas, je n'ai malheureusement pas le temps matériel en ce moment de reprendre ces travaux. Dés que ce sera le cas, je reprendrai tout cela plus sérieusement, et ne manquerait pas de compléter ce post que du coup je me permets de maintenir ouvert pour le moment.

    Merci encore.
    Fichiers attachés Fichiers attachés
    Une technologie n'est récalcitrante que par ce qu'on ne la connait et/ou comprend pas, rarement par ce qu'elle est mal faite.
    Et pour cesser de subir une technologie récalcitrante, n'hésitez surtout pas à visiter les Guides/Faq du site !

    Voici une liste non exhaustive des tutoriels qui me sont le plus familiers :
    Tout sur Java, du débutant au pro : https://java.developpez.com/cours/
    Tout sur les réseaux : https://reseau.developpez.com/cours/
    Tout sur les systèmes d'exploitation : https://systeme.developpez.com/cours/
    Tout sur le matériel : https://hardware.developpez.com/cours/

  6. #6
    Membre Expert
    Avatar de yotta
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    Septembre 2006
    Messages
    1 088
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Technicien maintenance
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2006
    Messages : 1 088
    Par défaut Problème réglé.
    Bonjour à vous,

    Ca y est, j'ai trouvé la solution à mon problème. J'ai donc procédé ainsi. Une partie de code lance mon application externe via un ProcessBuilder sur lequel une redirection du flux de sortie standard vers le flux standard Java.
    En fait, je n'avais pas compris correctement les explications dispensées en Anglais dans les spécifications de l'API Java. Je pensais que cette redirection orientait le flux de sortie standard du programme cible vers le flux d'entrée de mon programme, soit, System.in. En fait, Ce n'est pas vraiment une redirection, c'est plutôt une capture du flux que l'on récupère en récupérant le plus simplement du monde par la méthode getInputStream du Process engendré. Et pour éviter de me heurter à une prise en charge spécifique du flux de sortie standard par l'application Blender, j'ai écrit un script Shell qui lance Blender. Du coup, Java ne lance plus Blender, mais le script et récupère donc le flux de sortie du script.
    Voilà ce que ça donne sous forme de code :

    // La partie de code qui lance l'application externe
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    List<String> ordre = Arrays.asList("/home/thierry/lanceur.sh", "1er paramètre du script", "Deuxième paramètre du script", "Troisième paramètre du script");// lanceur.sh lance l'application Blender en lui passant ces paramètres plus d'autres.
    ProcessBuilder generateurInstanceBlender = new ProcessBuilder(ordre);
    generateurInstanceBlender.redirectOutput(ProcessBuilder.Redirect.PIPE);
    Process blender = generateurInstanceBlender.start();
    EcouteProcessusBlender moniteur = new EcouteProcessusBlender(blender.getInputStream());
    moniteur.start();
    blender.waitFor();
    moniteur.arret();
    // La classe EcouteurProcessusBlender

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    public class EcouteurProcessusBlender extends Thread {
     
    private volatile Thread moniteur;
    private final InputStream fluxin;
     
       public EcouteurProcessusBlender(InputStream fluxin) {
          this.fluxin = fluxin;
          }
     
       public void start() {
          moniteur = new Thread(this);
          moniteur.start();
          }
     
       public void arret() {
          moniteur = null;
          }
     
       public void run() {
          Thread comparateur = Thread.currentThread();
          BufferedReader lecteur = new BufferedReader(new InputStreamReader(fluxin));
          while (comparateur == moniteur) {
             try {
                     while (fluxin.available() > 0) System.out.println(fluxin.readLine());
                     }
             catch (IOException e) {
                Logger.getLogger(EcouteProcessusBlender.class.getName()).log(Level.SEVERE, null, e);
                }
             }
          }
       }
    Comme j'utilise un BufferedReader.readLine() avec succès, cela signifie que l'application Blender envoie bien les retours chariot en fin de ligne. Sans quoi, je ne réceptionnerai les données qu'en sortie de programme, voir rien.

    Merci pour votre aide.
    Une technologie n'est récalcitrante que par ce qu'on ne la connait et/ou comprend pas, rarement par ce qu'elle est mal faite.
    Et pour cesser de subir une technologie récalcitrante, n'hésitez surtout pas à visiter les Guides/Faq du site !

    Voici une liste non exhaustive des tutoriels qui me sont le plus familiers :
    Tout sur Java, du débutant au pro : https://java.developpez.com/cours/
    Tout sur les réseaux : https://reseau.developpez.com/cours/
    Tout sur les systèmes d'exploitation : https://systeme.developpez.com/cours/
    Tout sur le matériel : https://hardware.developpez.com/cours/

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Problème avec Process.exec() (Ligne de commande complexe)
    Par nanath02 dans le forum Débuter avec Java
    Réponses: 3
    Dernier message: 10/09/2014, 16h48
  2. Problème avec "Process.GetProcessesByName"
    Par jacko842 dans le forum Windows Forms
    Réponses: 14
    Dernier message: 21/12/2011, 19h09
  3. petit Problème avec (Process.Start)
    Par kazylax dans le forum C#
    Réponses: 2
    Dernier message: 01/10/2011, 15h21
  4. Réponses: 2
    Dernier message: 11/02/2009, 23h30
  5. problème avec getInputStream()
    Par Aethis dans le forum Langage
    Réponses: 4
    Dernier message: 29/06/2006, 11h55

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo