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 :

Problème avec Process.getInputStream()


Sujet :

Entrée/Sortie Java

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

    Informations professionnelles :
    Activité : Technicien maintenance
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2006
    Messages : 1 088
    Points : 1 540
    Points
    1 540
    Par défaut Problème avec Process.getInputStream()
    Bonjour,
    Après plusieurs jours de torture mentale, je me résous à venir vous casser un peu les pieds.
    J'évolue sous Windows 7 64bits, avec un environnement Java 1.0.8_60 64bits.
    Dans mon programme, je cherche à récupérer le flux d'un process représentant le lancement d'un programme exécutable externe.
    En l'occurrence, je dois utiliser mencoder.exe. Pour ceux qui ne connaissent pas, il s'agit d'un des éléments de MPlayer, player multimédia opensource bien connu.
    Je me sers de ce dernier pour produire une vidéo à partir d'un ensemble d'images Jpeg.
    Voilà pour le contexte.
    Et maintenant, le problème :
    Lorsque je lance mencoder.exe à la main, en ligne de commande avec tous ses paramètres pour la production de la vidéo, tout se passe à la perfection. Je remarque que ce petit programme est verbeux par la présence de nombreuses lignes dans ma fenêtre DOS. Bref, ça m'arrange car cette verbosité va me permettre d'éffectuer un suivi de la tâche de création vidéo en examinant le flux des messages de la console.
    Ce flux est récupérable en gros de deux manières, soit directement auprès d'une instance de la classe Process, par sa méthode getInputStream(), soit en utilisant ProcessBuilder afin de rediriger le flux vers notre programme.
    Seulement voilà, quelle que soit la solution "découte" adoptée, ça ne fonctionne pas correctement.
    Prenons un exemple avec 300 photos. Je demande à mencoder.exe d'en faire une vidéo mpeg4 en ligne de commande, pas de problème. Mais si j'exécute mencoder.exe avec les mêmes paramètres soit par Runtime.exec soit par ProcessBuilder.start, je récupère bien le flux de sortie console, et ce dernier contient bien la même chose que ce que je vois en ligne de commande, mais pour une raison qui me dépasse totalement, le flux s'interrompt après avoir en gros récupérer les 40 première lignes de verbosité ?!.... alors qu'avec 300 images, on obtient normalement un peu plus de 300 lignes.
    J'ai alors tenté de lancer mencoder différemment, en créant un batch qui lance mencoder. Et dans ce cas, mon code lance le batch, il ne lance plus directement mencoder.exe, mais là aussi, le flux s'interrompt, et toujours au même endroit. J'ai alors remplacé mon lot de 300 photos par 300 autres, même résultat, avec toujours une interruption de flux sans erreur après réception du même nombre de lignes de verbosité...
    Si quelqu'un a une idée ?
    Dés que je serai rentré à la maison, j'ajouterai quelques pièces jointes pour montrer la différence de verbosité obtenue dans les deux cas, et le code employé.
    Merci à vous...

  2. #2
    Expert éminent sénior
    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
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Salut,

    Tu gères bien les autres flux ?

    Si tu n'utilises pas le flux d'entrée il est toujours préférable de le fermer au plus tôt.
    Pour le flux d'erreur, le plus simple est de le fusionner avec la sortie standard (via redirectErrorStream(true)) ou de le renvoyer vers la console (à partir de Java 7, via redirectError(Redirect.INHERIT))


    Sinon montre ton code de lecture...


    a++

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

    Informations professionnelles :
    Activité : Technicien maintenance
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2006
    Messages : 1 088
    Points : 1 540
    Points
    1 540
    Par défaut
    Salut Adiguba,
    Merci pour ta réponse. Malheureusement, je n'ai rien dans le flux d'erreur. Pour en être sûr, j'ai créé deux threads distincts, un qui s'occupe d'InputStream et l'autre d'ErrorStream. Comme décrit dans mes explications, la verbosité s'arrête après quelques lignes, et il n'y a strictement rien qui tombe dans le flux d'erreur.
    Cependant, j'ai remarqué qu'en lançant mencoder.exe directement depuis mon code java, quelle que soit la méthode employée pour lui passer ses paramètres, ce dernier ne les prends jamais en compte. Comme il me génère bien une vidéo, je n'avais pas étudié en détail le contenu des lignes de verbosité, mais en fait, elles indiquent toutes à chaque image qu'aucune dimension n'a été fournie, aucun codec et quelques autres réglages. Par contre, il prend bien le premier paramètre qui lui indique où se trouvent les fichiers jpeg, et il capte bien le dernier paramètre qui définit le nom du fichier de sortie .avi ???

    Donc, comme en contre-partie ça fonctionne très bien en lançant mencoder.exe depuis un batch, j'ai finalisé mon batch de lancement comme suit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    Contenu de mencoder.bat :
    .\mencoder mf://*.jpg -mf w=%1:h=%2:fps=%3:type=jpg -ovc lavc -lavcopts vcodec=%4 -oac copy -o %5
    
    %1 : largeur de l'image en pixel, %2 hauteur, %3 débit en nombre d'images par seconde, %4 codec vidéo, et %5 pour le nom de fichier de sortie.
    
    Exemple d'utilisation de mencoder.bat :
    
    mencoder.bat 1024 768 25 mpeg4 test.Avi
    Donc, lorsque je lance mencoder.bat depuis mon code java avec les paramètres indiqués ci-dessus, mencoder se lance et interprète bien tous les paramètres. Mais toujours pareil, sa verbosité s'arrête au même endroit....
    J'ai aussi créé un deuxième fichier bat un peu différent :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Contenu de mencoder_rev2.bat :
     
    CMD /C "mencoder.exe mf://*.jpg -mf w=%1:h=%2:fps=%3:type=jpg -ovc lavc -lavcopts vcodec=%4 -oac copy -o %5"
    J'obtiens exactement le même résultat.....
    Pour illustrer tout ça, j'ai ajouté deux pièces jointes à cette discussion, Pièce jointe 187780 qui correspond à la sortie verbeuse obtenue lors d'un lancement manuel en ligne de commande de mon batch "mencoder.bat", et Pièce jointe 187781 qui correspond à la verbosité obtenue depuis mon code Java "recupMessages.class" dans tous les tests réalisés.

    Et ci-dessous, le code java utilisé pour lire cette verbosité dans ses deux déclinaisons, Runtime.exec et ProcessBuilder.start :

    Version utilisant la méthode exec de la classe Runtime :

    Code du Thread lanceur :

    Depuis la fenêtre graphique de mon programme, un clique sur un bouton "Créer séquence vidéo" réalise 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
    23
        private void Cmd_CreerSequenceActionPerformed(java.awt.event.ActionEvent evt) {                                                  
            System.out.println("Lancement de la création de la vidéo...");
            ecouteurMEncoder ecoute = new ecouteurMEncoder(cheminSortiePhotos);
            ecoute.ajouteEcouteur(this);
            ecoute.start();
        }                                                 
     
    Cette fenêtre implémente une interface à moi qui lui permet de récupérer les informations concernant le travail de "ecoute". D'où "ecoute.ajouteEcouteur(this);". Cette interface définie trois méthodes dont voici l'implémentation :
     
        @Override
        public void debutEncodage(String msg) {
            System.out.println("Début: " + msg);
            }
     
        @Override
        public void finEncodage(String msg) {
            System.out.println("Fin: " + msg);
            }
     
        @Override
        public void erreurEncodage(String msg) {
            System.out.println("ERREUR !\n" + msg);
            }
    Voilà le code de la classe ecouteurMEncoder :

    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
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
     
    package classes;
     
    import interfaces.Ecouteur;
    import interfaces.EcouteurEncodage;
    import java.io.BufferedReader;
    import java.io.File;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.util.ArrayList;
    import java.util.logging.Level;
    import java.util.logging.Logger;
     
    public class ecouteurMEncoder extends Thread implements Ecouteur {
     
        final ArrayList<EcouteurEncodage> ecouteurs = new ArrayList();
        final String chemin;
        final int DEBUT = 1;
        final int FIN = 2;
        final int ERREUR = 3;
     
        private volatile Thread moniteur;
     
        public ecouteurMEncoder(String chemin) {
            // Ici, le chemin correspond au chemin pleinnement qualifié d'accès au dossier contenant les images, et mencoder.exe
            this.chemin = chemin; 
            setDaemon(true);
            }
     
        @Override
        public void start() {
            moniteur = new Thread(this);
            moniteur.start();
            }
     
        public boolean arret() {
            boolean reponse;
            moniteur = null;
            reponse = (moniteur == null);
            return reponse;
            }
     
        @Override
        @SuppressWarnings("SleepWhileInLoop")
        public void run() {
            envoiMessage("Thread ecouteur d'encodage démarré...", DEBUT);
            String[] commande = {chemin + File.separator + "mencoder.bat", "1024", "768", "25", "mpeg4", "testAvecRuntime.avi"};
            //String[] commande = {chemin + File.separator + "mencoder_rev2.bat", "1024", "768", "25", "mpeg4", "testAvecRuntime.avi"};
            Process mencoder;
            BufferedReader sortieConsole;
            try {
                // Il n'y a pas à ajouter de directives environnementales, d'où le null
                mencoder = Runtime.getRuntime().exec(commande, null, new File(chemin));
                // Récupération du flux de verbosité de mon shell natif dans lequel s'exécute "commande"
                sortieConsole = new BufferedReader(new InputStreamReader(mencoder.getInputStream()));
                // Instanciation et initialisation de mon Thread d'écoute de flux
                recupMessages recuperateur = new recupMessages(sortieConsole);
                // Ajout de l'écoute d'informations issues de recuperateur
                recuperateur.ajouteEcouteur(this);
                // Attente de la fin du processus externe...
                mencoder.waitFor();
                }
            catch (IOException | InterruptedException ex) {
                Logger.getLogger(ecouteurMEncoder.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
     
        public void ajouteEcouteur(EcouteurEncodage ecouteur) {
            if (!ecouteurs.contains(ecouteur)) ecouteurs.add(ecouteur);
            }
     
        public void retireEcouteur(EcouteurEncodage ecouteur) {
            if (ecouteurs.contains(ecouteur)) ecouteurs.remove(ecouteur);
            }
     
        private void envoiMessage(String msg, int type) {
            switch (type) {
                case DEBUT:
                    ecouteurs.stream().forEach((ect) -> {
                        ect.debutEncodage(msg);
                        });
                    break;
     
                case FIN:
                    ecouteurs.stream().forEach((ect) -> {
                        ect.finEncodage(msg);
                        });
                    break;
     
                case ERREUR:
                    ecouteurs.stream().forEach((ect) -> {
                        ect.erreurEncodage(msg);
                        });
                    break;
                }
            }
     
        @Override
        public void declenchement(String message) {
            envoiMessage(message, DEBUT);
            }
        }
    Code du Thread de récupération de la sortie verbeuse : recupeMessages.class

    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
    52
    53
    54
     
    package classes;
     
    import interfaces.Ecouteur;
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.logging.Level;
    import java.util.logging.Logger;
     
    public class recupMessages implements Runnable {
     
        private final BufferedReader lecteur;
        private final Thread t;
        final ArrayList<Ecouteur> ecouteurs = new ArrayList();
     
        public recupMessages(BufferedReader lecteur) {
            this.lecteur = lecteur;
            t = new Thread(this);
            init();
            }
     
        private void init() {
            t.start();
            }
     
        public void ajouteEcouteur(Ecouteur ecouteur) {
            if (!ecouteurs.contains(ecouteur)) ecouteurs.add(ecouteur);
            }
     
        public void retireEcouteur(Ecouteur ecouteur) {
            if (ecouteurs.contains(ecouteur)) ecouteurs.remove(ecouteur);
            }
     
        @Override
        @SuppressWarnings("SleepWhileInLoop")
        public void run() {
            Thread comp = Thread.currentThread();
            while (comp == t) {
                try {
                    while (lecteur.ready()) envoiMessage(lecteur.readLine());
                    }
                catch (IOException ex) {
                    Logger.getLogger(recupMessages.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
            }
     
        private void envoiMessage(String message) {
            ecouteurs.stream().forEach((ect) -> {
                ect.declenchement(message);
                });
            }
    }
    Version utilisant la méthode start de la classe ProcessBuilder :

    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
    Seule la classe ecouteurMEncoder change. Plus précisément, sa méthode run, le reste ne change pas. Donc, voici uniquement le code de sa méthode run.
     
        @Override
        @SuppressWarnings("SleepWhileInLoop")
        public void run() {
            envoiMessage("Thread ecouteur d'encodage démarré...", DEBUT);
            String[] commande = {chemin + File.separator + "mencoder.bat", "1024", "768", "25", "mpeg4", "testAvecRuntime.avi"};
            //String[] commande = {chemin + File.separator + "mencoder_rev2.bat", "1024", "768", "25", "mpeg4", "testAvecRuntime.avi"};
            Process mencoder;
            BufferedReader sortieConsole;
            try {
                List<String> ordre = Arrays.asList(chemin + File.separator + "mencoder.bat", "1024", "768", "25", "mpeg4", "test.avi");// lanceur.sh lance l'application Blender en lui passant ces paramètres plus d'autres.
                ProcessBuilder generateurInstanceMEncoder = new ProcessBuilder(ordre);
                generateurInstanceMEncoder.directory(new File(chemin + File.separator));
                generateurInstanceMEncoder.redirectOutput(ProcessBuilder.Redirect.PIPE);
                Process encodage = generateurInstanceMEncoder.start();
                sortieConsole = new BufferedReader(new InputStreamReader(encodage.getInputStream()));
                recupMessages recuperateur = new recupMessages(sortieConsole);
                recuperateur.ajouteEcouteur(this);
                encodage.waitFor();
                }
            catch (IOException | InterruptedException ex) {
                Logger.getLogger(ecouteurMEncoder.class.getName()).log(Level.SEVERE, null, ex);
                }
            }

    Voilà,
    tu as tout ce qu'il faut pour reproduire mon problème. il te faut juste mencoder.exe, qui fonctionne de manière totalement autonome, téléchargeable ici, et un lot de fichiers jpeg, peu importe le nombre, mais plus d'une dizaine sinon on risque d'atteindre la fin du traitement avant le blocage du flux. La nature des photos est sans importance, 300x la même fera l'affaire. Il faut juste que ce soient des Jpeg de même résolution, et que leur nom se termine par une indentation, exemple : test_image1.jpg, test_image2.jpg, etc...

  4. #4
    Expert éminent sénior
    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
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Tu ne traites pas le flux d'erreur.
    Si mencoder écrit sur le flux d'erreur c'est "normal" que cela se bloque à un moment où à un autre.

    Si tu ne les traites pas, rajoutes ceci avant de démarrer ton process :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    	generateurInstanceMEncoder.redirectError(ProcessBuilder.Redirect.INHERIT);
    Cela va recopier automatiquement sur le flux d'erreur de ton process...

    Idem pour le flux d'entrée, même s'il serait plutôt préférable de le fermer immédiatement après la création du process :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    encodage.getOutputStream().close();

    Au passage si tu ne traites qu'un seul flux inutile de créer un nouveau thread : tu peux bien le faire dans le thread courant, et donc directement après la création de ton process.


    Enfin utilises le try-with-ressource pour la libération des ressources.


    a++

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

    Informations professionnelles :
    Activité : Technicien maintenance
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2006
    Messages : 1 088
    Points : 1 540
    Points
    1 540
    Par défaut
    Un grand merci adiGuba !
    J'ai suivi tes conseils et commencé par fermer le flux de sortie de mon process tout de suite après création. Puis, j'ai aussi pratiqué la redirection du flux d'erreur. Et maintenant, tout fonctionne à merveille. Je capture intégralement la verbosité de mencoder, je vais pouvoir faire ma jauge et passer à la suite. Je vais bien sûr prendre le temps d'y regarder de plus près parce que je n'ai pas encore tout compris, notamment pour ce qui concerne ton dernier conseil avec "try-with-ressource pour la libération des ressources"...
    Pardonnes-moi mais je suis purement autodidacte, lu comme ça, ça ne me parle pas. Mais je vais gratter, si je n'y arrive pas, je me permettrai peut-être de te solliciter.
    Encore merci !

  6. #6
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 560
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 560
    Points : 21 622
    Points
    21 622
    Par défaut
    Hello,

    pendant qu'on y est sur les éléments importants. Cette ligne :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    while (lecteur.ready()) envoiMessage(lecteur.readLine());
    Ça veut dire qu'on arrête le traitement si par hasard lecteur.ready() devient faux.
    Ouais non, c'est probablement pas ce que tu veux. J'imagine que tu n'as pas l'intention de t'arrêter avant la fin, donc non, ready() ne fait pas ce que tu crois.

    En fait, Reader.ready() et InputStream.ready() ne servent pas à grand-chose, et quand ils sont utilisés, c'est en général parce que le programmeur ne comprenait pas et qu'il n'aurait pas dû faire ça.
    Il vaut mieux faire comme si ready() n'existait pas et ne jamais s'en servir. Il sera toujours temps d'y revenir quand tu comprendras absolument tout du fonctionnement des IO et que tu te diras que tu es dans un cas exceptionnel qui a besoin de ça.

    La boucle devrait s'arrêter quand il n'y a plus de ligne à lire. Ça ce sera très bien.

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

    Informations professionnelles :
    Activité : Technicien maintenance
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2006
    Messages : 1 088
    Points : 1 540
    Points
    1 540
    Par défaut
    Salut Thelvin,
    Merci pour ces précisions. De mon côté, j'ai compris ce que voulait dire "try with ressource". En fait, ça revient à préciser que l'on désire "rattacher" une ou plusieurs classes closeable au bloc de code try, ce qui a pour effet que lorsque la JVM termine le bloc de code, elle prend l'initiative d'invoquer les méthodes de fermetures des classes déclarées dans le try. Une précision serait nécessaire toutefois. Faut-il distinguer les actions "quitter le bloc de code try" et "terminer le bloc de code try" dans ce contexte ? En d'autres termes, s'il survient une exception dans le bloc de code try with ressource, le fait de le quitter pour se rendre dans le bloc de code catch revient-il au même que de terminer normalement le bloc de code try pour ce mécanisme try with ressource ?
    En fait, dans la documentation parcourue pour comprendre ce mécanisme, je n'ai recensé que des concepts de terminaisons de bloc de code. Malheureusement, dans mon esprit, je fais la distinction entre quitter, et terminer. Du coup, ça me trouble suffisamment pour que je me poses cette question.
    Pour ce qui est de mes problèmes de lecture de flux verbeux de mencoder, je crois que j'ai compris exactement ce qui se passait. Je vais essayer de le décrire sans être trop long.
    Comme j'utilise mencoder.exe de manière autonome, en dehors de son "environnement naturelle" qui est MPlayer, il lui manque quelques billes, notamment pour le sous-titrage. Bien que je ne m'en serve pas, mencoder s'en rend bien compte. Du coup, il envoi bien de l'information dans le flux d'erreur. Comme de mon côté je me contentais de lire le flux de sortie standard, et que mencoder semble fermer ce flux pour écrire dans le flux d'erreur puis revenir sur le flux de sortie standard qui ne semble plus être le même que celui auquel mon BufferedReader est rattaché ce dernier ne reçoit plus la suite.
    En effet, en examinant ce fameux flux d'erreur, j'ai remarqué toutes les lignes verbeuses envoyées par mencoder indiquant l'absence de telle ou telle bille...
    Ce qui m'a permis de comprendre que le flux de sortie standard est fermé, c'est d'avoir mis en place le fameux try with ressource.
    Évidemment, pour transformer mon try standard en try with ressource, j'ai ajouté entre parenthèse la déclaration et l'instanciation d'un BufferedReader que j'utilise ensuite pour lire le flux de sortie standard. Du coup, quand mencoder ferme le flux de sortie standard (ou le suspend) pour écrire dans le flux d'erreur, mon readLine() quitte normalement, sans erreurs, et ma boucle reprend. Sauf qu'en reprenant, elle termine aussi le bloc de code try with ressource puisque ce dernier est dans ma boucle. Du coup, BufferedReader est fermé, et à la boucle suivante, je fais un ready() sur un BufferedReader fermé, alors que jusque là, j'étais persuadé que mon code attendait désespérément dans son readLine(). Comme je ne traite probablement pas correctement l'exception dans la classe qui fournie le BufferedReader, avec un try standard, je ne "perçois" pas cette dernière. Mais avec un try with ressource, cela m'oblige à fournir le flux et à construire l'instance de BufferedReader en tant que ressource pour mon try, du coup, l'exception est correctement levée. Une exception claire qui me dit clairement que le flux est fermé et que l'exception est à l'origine de la méthode ready(). C'est pourquoi dans sa première version, ma lecture semblait s'interrompre. Il va me falloir traiter les exception de manière plus fine dans le reste de mon programme pour ne plus me faire piéger...
    Cependant, maintenant et dans l'absolue, ça fonctionne suffisamment bien dans le sens où j'obtiens la vidéo demandée, et je peux suivre sa création.

    Revenons sur ta précision concernant cette fameuse méthode ready().
    Si je comprends bien, tu me proposes d'éviter l'usage d'un Reader ?
    En effet, que je sache, ce sont les seuls permettant une lecture ligne par ligne sans se prendre la tête. Mais sans cette méthode ready(), je ne vois pas comment les utiliser ?!...
    Et de toute façon, comme je l'ai dit au début de mon post, lorsque j'en étais encore à ne rien comprendre à ce qui se passait, j'ai tenté de remplacer BufferedReader par une lecture directe du InputStream, octet par octet, et sans succès. Le blocage est vraiment lié à une seule chose, le fait que j'utilise mencoder.exe hors de son environnement naturelle. Si je l'y avait laissé, il n'y aurait probablement eu aucun flux d'erreur, donc, aucun blocage à mon niveau. Je penses que c'est le simple fait que mencoder écrive alternativement dans le flux de sortie standard et dans le flux de sortie d'erreur que ma méthode de lecture coince.
    Dans mon cas, je me sert de ready() comme d'un repère, afin de m'assurer que mon flux est connecté, et que je peux faire mon readLine() en toute tranquillité. Donc, pour moi, ready() est vraiment utile. Ensuite, de toute façon, readLine() est "bloquant" puisqu'il ne se passera plus rien tant qu'il n'aura pas réceptionné un retour chariot. Je ne peux pas m'appuyer sur un Timeout, je n'ai absolument aucune idée du temps qui se déroule dans le traitement entre chaque image. J'ai remarqué dans l'usage que ce temps peut varier de moins d'une seconde à plusieurs dizaines....
    En d'autre termes, il est normal que mon flux ne réceptionne rien pendant plusieurs dizaines de secondes sans pour autant cesser de l'écouter.

    En tout cas, merci encore à adiGuba pour son aide, sans quoi, je crois bien que j'y serai encore.

  8. #8
    Expert éminent sénior
    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
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Le try-with-ressource appelera "close()" quoi qu'il arrive (exception ou return compris).
    C'est justement là tout son intérêt.


    Je n'ai pas trop compris ton explication pour le flux d'erreur.
    En fait mencoder écrit dans son flux d'erreur (qui est en fait un buffer entre les deux applications)
    Si tu ne lis pas le flux, le buffer va se remplir, et provoquer un blocage de mencoder (le print() ne rendra pas la main).
    Il ne pourra être débloqué que lorsque tu auras lu le flux.
    C'est aussi simple que cela.


    Citation Envoyé par yotta Voir le message
    Revenons sur ta précision concernant cette fameuse méthode ready().
    Si je comprends bien, tu me proposes d'éviter l'usage d'un Reader ?
    Non : tu utilises un Reader, mais pas la méthode ready().
    ready() sert juste à regarder à un moment précis s'il y a des données dans le flux, mais seulement si on ne veut pas faire une lecture bloquante.

    Sinon cela ne sert à rien et c'est même contre-performant.
    En fait ton code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    while (lecteur.ready()) envoiMessage(lecteur.readLine());
    Devrait plutôt ressembler à cela :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    String line;
    while ( (line=lecture.readLine()) != null) {
    	envoiMessage(line);
    }
    Avec ready() tu regardes d'abord s'il y a quelque chose dans le flux.
    C'est inutile, et même pire c'est consommateur de CPU lorsqu'il n'y a rien à lire dans le flux, car tu va faire des appels incessants...



    a++

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

    Informations professionnelles :
    Activité : Technicien maintenance
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2006
    Messages : 1 088
    Points : 1 540
    Points
    1 540
    Par défaut
    Salut adiGuba,
    C'est parfait. Maintenant j'ai tout compris, y-compris pourquoi ma vidéo se générait uniquement après que je quitte mon programme Java. je suppose qu'en libérant le flux que je n'écoutait pas, ce dernier a été restitué à explorer.exe qui a permis à mencoder de le voir enfin se vider et poursuivre...
    On en apprend tous les jours.
    Merci.

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

Discussions similaires

  1. Problème avec Process.getInputStream()
    Par yotta dans le forum Général Java
    Réponses: 5
    Dernier message: 23/02/2015, 18h43
  2. 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
  3. Problème avec "Process.GetProcessesByName"
    Par jacko842 dans le forum Windows Forms
    Réponses: 14
    Dernier message: 21/12/2011, 19h09
  4. petit Problème avec (Process.Start)
    Par kazylax dans le forum C#
    Réponses: 2
    Dernier message: 01/10/2011, 15h21
  5. Réponses: 2
    Dernier message: 11/02/2009, 23h30

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