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

Entrée/Sortie Java Discussion :

Runtime.getRuntime().exec() vers ProcessConsumer


Sujet :

Entrée/Sortie Java

  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    268
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 268
    Par défaut Runtime.getRuntime().exec() vers ProcessConsumer
    Après avoir lu le blog d'adiGuba (un grand merci !) j'en renvoie à mon histoire de Lancement d'un batch.
    Mon problème maintenant, c'est de récupérer les flux. Avant, avec Runtime.exec(), je faisais :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    	String ligneOK;
    	BufferedReader sortie = new BufferedReader(new InputStreamReader(proc.getInputStream()));
    	while ( (ligneOK = sortie.readLine()) != null ) {
    		this.log(" "+ligneOK);
    	}
    	sortie.close();
    et pareil pour le stream d'erreur.

    Mais maintenant, (avec l'aide donc d'adiGuba et de mon ancien post), je tente de faire la même chose, mais j'obtiens une erreur "Stream closed".

    La partie
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    	monPC.output( new FileOutputStream("out.txt") ).error( new FileOutputStream("err.txt") )
    n'est donc pas intéressante puisque je ne veux pas des fichiers.
    Cependant, les fichiers sont crées, donc ça marche.

    J'essaie donc
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    	// On crée les StringBuilder qui contiendront les sorties du process :
    	StringBuilder out = new StringBuilder();
    	StringBuilder err = new StringBuilder();
    mais du coup, je ne sais pas du tout comment traiter mes "BufferedReader sortie" (celui du runtime.exec() normal).
    Je tiens à préciser que je ne maitrise pas du tout toutes ces notions de buffer, et que je sais pas trop quoi chercher

    [Edit]
    Après un peu plus de recherche, et toujours sur le blog, je test :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    	PipedReader lignesOk = new PipedReader(); 
    	PipedReader lignesErr = new PipedReader(); 
     
    	pc.output(new PipedWriter(lignesOk)).error(new PipedWriter(lignesErr));
    mais le
    reste toujours bloqué, comme avant (comme par un ancien proc.waitFor()), et apparement toujours au moment du remplissage des flux. Je me doute que le problème vient de la ligne de commande, mais pourquoi dans le cas de fichiers, ça marche, alors qu'avec des readers/writer ça ne marche plus ???

    Suis-je obligé de passer par des fichiers temporaires que je lirais après le "monPC.consume()" ?

  2. #2
    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,

    Si tu utilises des StringBuilder il te suffit de lire la chaine générée qui contiendra la totalité de la réponse (mais cela peut être consommateur de mémoire si la sortie est très grande).

    Si tu utilises des PipedReader/Writer tu dois faire un consumeInBackground() car la lecture doit être faite en parallèle... mais cela revient au même problème qu'à l'origine...


    Sinon si tu as un besoin plus spécifique tu peux définir tes propres "appender".



    D'où ma question : que va tu faire des données en sortie ?


    a++

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    268
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 268
    Par défaut
    Alors, en passant par des fichiers (avec lecture tout de suite après), celà fonctionne.

    Mais avec PipedReader/Writer en consumeInBackground(), toujours le même problème. Et je serais totalement incapable de définir mes propres "appender".

    [EDIT]
    En fait non, l'appli se bloque sur le
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    // lignesOk est le PipedReader
    BufferedReader sortie = new BufferedReader(lignesOk);
    while ( (ligneOK = sortie.readLine()) != null )
    // etc ...
    Ce qui est bizarre, c'est que suivant ce que donne le batch, il bloque soit au flux, soit à l'exécution (que ce soit runtime.exec() ou ta librairie) (sauf dans le cas où les flux sont des fichiers, comme je l'ai dis précédement)
    [/EDIT]

    Les données en sorties sont en fait pour un affichage dans un compte rendu de l'application.


    Petite remarque : Je test donc en passant par des fichiers. Mon batch est du style :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    @echo off
    echo lancement
    "c:/BLABLABLA/prog.exe"
    echo termine
    J'ai bien les 2 echo dans le "output", mais l'affichage du "prog.exe" part directement dans le "error"

  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
    Citation Envoyé par JohnNC Voir le message
    Mais avec PipedReader/Writer en consumeInBackground(), toujours le même problème.
    Comme tu utilises cela sur les 2 sorties (standards et erreurs), il faut créer deux threads de lecture sinon tu peux avoir des interblocages (cela revient au même problème qu'utilsier exec() directement).


    Citation Envoyé par JohnNC Voir le message
    Les données en sorties sont en fait pour un affichage dans un compte rendu de l'application.
    Oui mais comment ?
    Dans tous tes codes tu essayes de faire des lectures lignes par lignes ? C'est une volonté particulière ou pas ?

    Citation Envoyé par JohnNC Voir le message
    J'ai bien les 2 echo dans le "output", mais l'affichage du "prog.exe" part directement dans le "error"
    Ca ca dépend complètement de ton "prog.exe"...


    a++

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    268
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 268
    Par défaut
    Désolé j'ai fais une petite édition entre temp, sur le "blocage".

    Alors :
    Citation Envoyé par adiGuba Voir le message
    Oui mais comment ?
    Dans tous tes codes tu essayes de faire des lectures lignes par lignes ? C'est une volonté particulière ou pas ?
    par un
    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
    String ligneOK;
    BufferedReader sortie = new BufferedReader(lignesOk);
    //BufferedReader sortie = new BufferedReader(new InputStreamReader(new FileInputStream(ficSTD)));
    while ( (ligneOK = sortie.readLine()) != null ) {
      // cr est un objet de compteRendu : un JPanel avec un JTextPane
      cr.log(" "+ligneOK);
    }
    sortie.close();
    // Suivi de
    String ligneErreur;
    BufferedReader sortieErr = new BufferedReader(lignesErr);
    //BufferedReader sortieErr = new BufferedReader(new InputStreamReader(new FileInputStream(ficERR)));
    while ( (ligneErreur = sortieErr.readLine()) != null ) {
      cr.logErreur(" "+ligneErreur);
    }
    sortieErr.close();
    Et ligne par ligne, heu bah parceque celui qui travaillait avant moi faisait comme ça et que j'ai copié/collé

    Citation Envoyé par adiGuba Voir le message
    Ca ca dépend complètement de ton "prog.exe"...
    Ben là, je vais laisser comme ça alors (il s'agit de pg_restore de postgres).

  6. #6
    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
    Si c'est pour afficher la sortie dans un JTextPane tu peux l'y envoyer directement plutôt que de faire une lecture ligne par ligne.


    Il te suffit d'implémenter l'interface Appendable et ses méthodes append(), sachant que ces méthodes seront appelées lorsque des données seront lu depuis le process, ce qui peut donner :
    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
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    class DocumentAppendable implements Appendable {
     
    	private final JTextComponent textComponent;
     
    	public DocumentAppendable(JTextComponent component) {
    		this.textComponent = component;
    	}
     
    	/**
             * Insertion d'un chaine dans un document,
             * en déplacant les scrollbars si neccessaire
             */
    	private void insertString(final String text) {
    		SwingUtilities.invokeLater(new Runnable() {
    			public void run() {
    				// On récupèrel e composant graphique
    				JTextComponent comp = DocumentAppendable.this.textComponent;
    				// On récupère le document associé
    				Document doc = comp.getDocument();
    				try {
    					// On insert le text recu à la fin du document :
    		            doc.insertString(doc.getLength(), text, null);
    		            // Et on déplace les scrollbars :
    		            comp.scrollRectToVisible( comp.modelToView(doc.getLength()));
    		        } catch (BadLocationException e) {
    		        	throw new RuntimeException(e); // Ne devrait pas arriver
    		        }
    			}
    		});
    	}
     
     
    	/*
    	 * On implémente les diverses méthodes de l'interface Appendable
    	 * en se contentant de renvoyer vers la méthode insertString() :
    	 * 
    	 */
     
    	public Appendable append(char c) throws IOException {
    		insertString(Character.toString(c));
    		return this;
    	}
    	public Appendable append(CharSequence csq) throws IOException {
    		insertString(csq.toString());
    		return this;
    	}
    	public Appendable append(CharSequence csq, int start, int end) throws IOException {
    		insertString(csq.subSequence(start, end).toString());
    		return this;
    	}
    }
    Exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    	sh.command("ma ligne de commande")
    		// On redirige la sortie standard vers le textpane
    		.output(new DocumentAppendable(monTextPane))
    		// On redirige la sortie d'erreur vers la sortie standard
    		.errorRedirect() 
    		.consume();

    a++

  7. #7
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    268
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 268
    Par défaut
    Merci pour cette info !

    [EDIT]Le errorRedirect() me donne un
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Caused by: java.lang.IllegalStateException: No ProcessBuilder
    	at com.developpez.adiguba.shell.ProcessConsumer.errorRedirect(ProcessConsumer.java:448)
    [/EDIT]

    Dernière question, est-ce que j'ai les messages dans l'ordre d'apparition du batch avec le errorRedirect ? (Ou si je met par exemple le même objet Appendable en output et error) ?

  8. #8
    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
    Citation Envoyé par JohnNC Voir le message
    [EDIT]Le errorRedirect() me donne un
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Caused by: java.lang.IllegalStateException: No ProcessBuilder
    	at com.developpez.adiguba.shell.ProcessConsumer.errorRedirect(ProcessConsumer.java:448)
    [/EDIT]
    Quel est le code correspondant et le stacktrace complet de l'exception ?

    Citation Envoyé par JohnNC Voir le message
    Dernière question, est-ce que j'ai les messages dans l'ordre d'apparition du batch avec le errorRedirect ? (Ou si je met par exemple le même objet Appendable en output et error) ?
    Si tu rediriges tout vers le même Appendable il est préférable d'utiliser errorRedirect() car la "redirection" est faite au lancement de l'exécutable et tout est lu par un seul thread. Sinon tu as deux threads de lecture et l'ordre peut donc varier quelque peu...


    a++

  9. #9
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    268
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 268
    Par défaut
    Voici le code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    ProcessBuilder proc2 = new ProcessBuilder(new String[] {batch});
    Process proc = proc2.start();
    proc2.redirectErrorStream(true);
     
    ProcessConsumer pc = new ProcessConsumer(proc) ;
     
    pc.output( new FileOutputStream("c:/tempSTD.txt") ).errorRedirect();
    pc.consume();
    Et le stackTrace :
    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
     // Catch général dans l'appli
    noyau.exception.NRuntimeException
    	at noyau.panneau.NPanneauExécution.exécuterDansMêmeThread(NPanneauExécution.java:208)
    	at noyau.panneau.NPanneauExécution.access$0(NPanneauExécution.java:197)
    	at noyau.panneau.NPanneauExécution$1.run(NPanneauExécution.java:176)
    // Exception levée
    Caused by: java.lang.IllegalStateException: No ProcessBuilder
    	at com.developpez.adiguba.shell.ProcessConsumer.errorRedirect(ProcessConsumer.java:448)
    	at maintenance.menus.MTBaseRestaurer.restaurer(MTBaseRestaurer.java:308)
    	at maintenance.menus.MTBaseRestaurer.restaurer(MTBaseRestaurer.java:277)
    	at maintenance.menus.MTBaseRestaurer.restaurer(MTBaseRestaurer.java:256)
    	at maintenance.menus.MTBaseRestaurer.lancerRestauration(MTBaseRestaurer.java:171)
    	at maintenance.menus.MTBaseRestaurer.exécuterAction(MTBaseRestaurer.java:80)
    	at noyau.panneau.NPanneauExécution.exécuterDansMêmeThread(NPanneauExécution.java:203)
    	... 2 more
    A noter peut être : Je n'utilise pas "Shell", j'utilise directement "ProcessConsumer"

  10. #10
    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
    Citation Envoyé par JohnNC Voir le message
    A noter peut être : Je n'utilise pas "Shell", j'utilise directement "ProcessConsumer"
    Dans ce cas passe lui directement le ProcessBuilder plutôt que le Process, sinon la redirection du flux d'erreur n'est pas possible...


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    ProcessConsumer pc = new ProcessConsumer(new ProcessBuilder(new String[] {batch})) ;
     
    pc.output( new FileOutputStream("c:/tempSTD.txt") ).errorRedirect();
    pc.consume();
    a++

  11. #11
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    268
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 268
    Par défaut
    Merci, ça marche ! (heu sauf toujours quand j'utilise des "flux" au lieu de fichiers, mais je m'en contenterais)

    Et un grand bravo pour le boulot fait sur l'API !

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

Discussions similaires

  1. [Système][Runtime]getRuntime().exec
    Par Neptune8 dans le forum API standards et tierces
    Réponses: 11
    Dernier message: 22/02/2011, 19h34
  2. Runtime.getRuntime().exec sous linux
    Par syl2095 dans le forum API standards et tierces
    Réponses: 1
    Dernier message: 30/01/2007, 12h56
  3. Runtime.getRuntime().exec(String) méthode sort
    Par devAd dans le forum Langage
    Réponses: 4
    Dernier message: 28/11/2006, 13h53
  4. [Runtime.getRuntime().exec] ouvrir un fichier ??
    Par miloud dans le forum API standards et tierces
    Réponses: 4
    Dernier message: 29/03/2006, 14h23
  5. [Swing] execution avec Runtime.getRuntime().exec
    Par benssj5 dans le forum AWT/Swing
    Réponses: 9
    Dernier message: 25/08/2004, 14h54

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