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.exec et gestion des flux


Sujet :

Entrée/Sortie Java

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Développeur Java
    Inscrit en
    Février 2015
    Messages
    30
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Vienne (Limousin)

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Février 2015
    Messages : 30
    Points : 27
    Points
    27
    Par défaut Runtime.exec et gestion des flux
    Bonjour amis développeurs,

    Je me suis inspiré de ce tuto ici pour lancer un exécutable externe dans mon application.

    Et ça marche... "Mais pourquoi poste t'il un sujet si ça marche?" vous demandez vous

    En fait l'exécutable écris des choses dans la console au cours de son exécution, mais ces informations ne sont affichées qu'à la fin de l'exécution et j'aimerai qu'elles le soient au moment ou elles sont écrites par l'exécutable.
    (J'affiche par exemple le temps restant estimé).

    J'ai essayé avec la Classe ProccesConsumer de l'API d'adiGuba ici mais j'ai le même résultat.
    Les lignes s'affichent uniquement a la fin de l'exécution du process.

    Voici mes classes.
    1. Process Launcher
    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
    103
    104
    105
    106
    107
    class ProcessLauncher
    {
    	final String inputFilePath;
    	Process process;
     
    	// Test API
    	// ProcessBuilder pb;
     
    	public ProcessLauncher(final String _inputFilePath)
    	{
    		inputFilePath = _inputFilePath;
    	}
     
    	public void exec(final boolean _waitForCompletion)
    	{
    		// On lance le processus
    		final Runtime runtime = Runtime.getRuntime();
     
    		try
    		{
    			process = runtime.exec(new String[] {
    					getExecutable().getAbsolutePath(),
    					"Name",
    					inputFilePath
    			});
     
    			// On ferme le flux STDIN du process (inutile)
    			process.getOutputStream().close();
     
    			// Ecoute stdout
    			new Thread(new DisplayStream(process.getInputStream(), System.out)).start();
     
    			// Ecoute stderr
    			new Thread(new ErrorStream(process.getErrorStream(), System.err)).start();
     
    			// TEST API
    			// final ProcessConsumer pc = new ProcessConsumer(process);
    			// pc.consume();
     
    			if (_waitForCompletion)
    			{
    				process.waitFor();
    			}
    		}
    		catch (final IOException _e)
    		{
    			DialogUtils.showErrorMessageBox(_e.getMessage());
    		}
     
    		catch (final InterruptedException _e)
    		{
    			DialogUtils.showErrorMessageBox(_e.getMessage());
    		}
    		catch (final SystemModelerException _e)
    		{
    			DialogUtils.showErrorMessageBox(_e.getMessage());
    		}
    	}
     
     
    	public boolean isRunning()
    	{
    		if (process == null)
    		{
    			return false;
    		}
     
    		try
    		{
    			process.exitValue();
    			return false;
    		}
    		catch (final Throwable t)
    		{
    		}
    		return true;
    	}
     
    	public Integer getExitValue()
    	{
    		try
    		{
    			return (process != null ? Integer.valueOf(process.exitValue()) : null);
    		}
    		catch (final Throwable t)
    		{
    			return null;
    		}
    	}
     
    	/**
             * Kills the running process
             */
    	public void killProcess()
    	{
    		try
    		{
    			if (process != null)
    			{
    				process.destroy();
    			}
    		}
    		catch (final Throwable t)
    		{
    		}
    	}
    }
    2. ErrorStream : Pour la gestion du flux stderr

    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
    inal class ErrorStream implements Runnable
    {
    	private final InputStream stream;
    	private final PrintStream printer;
     
    	ErrorStream(final InputStream _stream, final PrintStream _printer)
    	{
    		stream = _stream;
    		printer = _printer;
    	}
     
    	private BufferedReader getBufferedReader(final InputStream is)
    	{
    		return new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));
    	}
     
    	@Override
    	public void run()
    	{
    		final BufferedReader br = getBufferedReader(stream);
    		String line = "";
    		try
    		{
    			final StringBuilder sb = new StringBuilder();
     
    			while ((line = br.readLine()) != null)
    			{
    				// System.out.print(line);
    				printer.println(line);
    				sb.append(line + "\n");
    			}
     
    			if (sb.length() > 0)
    			{
    				DialogUtils.showErrorMessageBox(sb.toString());
    			}
    		}
    		catch (final IOException e)
    		{
    			Debug.logEvent(EventType.ERROR, e);
    		}
    		finally
    		{
    			stream.close();
    		}
    	}
    }
    3.DisplayStream Pour la gestion du stdout
    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
    final class DisplayStream implements Runnable
    {
    	private final InputStream stream;
    	private final PrintStream printer;
     
    	DisplayStream(final InputStream _stream, final PrintStream _printer)
    	{
    		stream = _stream;
    		printer = _printer;
    	}
     
    	private BufferedReader getBufferedReader(final InputStream is)
    	{
    		return new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));
    	}
     
    	@Override
    	public void run()
    	{
    		final BufferedReader br = getBufferedReader(stream);
    		String line = "";
    		try
    		{
    			final StringBuilder sb = new StringBuilder();
     
    			while ((line = br.readLine()) != null)
    			{
    				// System.out.println(line);
    				printer.println(line);
    				sb.append(line + "\n");
    			}
     
    			if (sb.length() > 0)
    			{
    				DialogUtils.showInformationMessageBox(sb.toString());
    			}
    		}
    		catch (final IOException e)
    		{
    			Debug.logEvent(EventType.ERROR, e);
    		}
    		finally
    		{
    			stream.close();
    		}
    	}
    }
    J'ai vérifié que l'exécutable renvoie bien plusieurs lignes et le code me semble correspondre aux infos que j'ai regroupé du coup j'avoue que je n'ai pas d'idée de solution.

    Merci pour vos futur idées.

  2. #2
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    Salut,

    C'est quoi l'exécutable externe ? Est-ce qu'il utilise bien les bons (pour l'OS) séparateurs de ligne pour chaque ligne et pas seulement à la fin ? C'est sous Windows ou Linux, tes tests ? Tu pourrais essayer de lire octet par octet le flux juste pour voir si ça lit bien au fur et à mesure. J'ai fait justement un petit exemple récemment sur le sujet, avec un programme externe Java (donc pas de souci pour le séparateur de ligne, vu que j'utilise des println) : l'exécuteur est tellement simple comparé à ce qu'il faut faire avec Runtime.exec, que c'est du masoschisme que de continuer à chercher à utiliser Runtime.exec. Et si ça ne fonctionne pas, c'est, à mon avis, un souci avec l'exécutable externe.

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


    Ton problème vient probablement du fait que tu utilises append(), qui écrit dans le buffer flux mais qui ne le valide pas...
    Donc soit tu rajoutes un flush() soit tu remplaces le append() par un println().


    Mais plus globalement à moins d'utiliser une version obsolète de Java, tout ceci est un peu obsolète.
    Il est grandement préférable d'utiliser ProcessBuilder et surtout la méthode inheritIO() qui associe les flux d'E/S du process appelant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    		Process process = new ProcessBuilder("prog", "arg1", "arg2", "...")
    			.inheritIO() // recopie les Entrées/Sortie sur la console du prog Java
    			.start();
    		process.waitFor();

    a++

  4. #4
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par adiGuba Voir le message
    Ton problème vient probablement du fait que tu utilises append(), qui écrit dans le buffer flux mais qui ne le valide pas...
    Donc soit tu rajoutes un flush() soit tu remplaces le append() par un println().
    L'append est fait sur le StringBuilder qui sert uniquement dans l'affichage final dans le dialogue, mais c'est bien println qui est utilisé sur le PrintStream, ou alors j'ai loupé quelque chose.

  5. #5
    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
    Citation Envoyé par joel.drigo Voir le message
    L'append est fait sur le StringBuilder qui sert uniquement dans l'affichage final dans le dialogue, mais c'est bien println qui est utilisé sur le PrintStream, ou alors j'ai loupé quelque chose.
    Mea Culpa !
    J'ai lu un peu trop vite...

  6. #6
    Nouveau membre du Club
    Homme Profil pro
    Développeur Java
    Inscrit en
    Février 2015
    Messages
    30
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Vienne (Limousin)

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Février 2015
    Messages : 30
    Points : 27
    Points
    27
    Par défaut
    Bonjour

    Citation Envoyé par joel.drigo Voir le message
    C'est quoi l'exécutable externe ?
    Alors c'est un exécutable qui est généré avec Visual Studio mais je n'ai pas accès au code.

    Citation Envoyé par joel.drigo Voir le message
    Est-ce qu'il utilise bien les bons (pour l'OS) séparateurs de ligne pour chaque ligne et pas seulement à la fin ?
    Il me semble. Comme je récupère bien ligne par ligne avec readLine.

    Citation Envoyé par joel.drigo Voir le message
    C'est sous Windows ou Linux, tes tests ?
    Sous Windows du coup mais je suppose que t'avais deviné (visual studio).

    Citation Envoyé par joel.drigo Voir le message
    J'ai fait justement un petit exemple récemment sur le sujet, avec un programme externe Java (donc pas de souci pour le séparateur de ligne, vu que j'utilise des println) : l'exécuteur est tellement simple comparé à ce qu'il faut faire avec Runtime.exec, que c'est du masochisme que de continuer à chercher à utiliser Runtime.exec.
    Ok je regarde ça merci

    Citation Envoyé par joel.drigo Voir le message
    Et si ça ne fonctionne pas, c'est, à mon avis, un souci avec l'exécutable externe.
    J'avais prévu aujourd'hui de faire un petit exe moi même pour etre sûr de bien avoir bon séparateurs pour voir si éventuellement ça venait de l'exe. Mais je vais jeter un coup d’œil d'abord à ton exemple.

    Merci encore

  7. #7
    Nouveau membre du Club
    Homme Profil pro
    Développeur Java
    Inscrit en
    Février 2015
    Messages
    30
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Vienne (Limousin)

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Février 2015
    Messages : 30
    Points : 27
    Points
    27
    Par défaut
    Bonjour,

    Citation Envoyé par adiGuba Voir le message
    Mais plus globalement à moins d'utiliser une version obsolète de Java, tout ceci est un peu obsolète.

    Il est grandement préférable d'utiliser ProcessBuilder et surtout la méthode inheritIO() qui associe les flux d'E/S du process appelant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    		Process process = new ProcessBuilder("prog", "arg1", "arg2", "...")
    			.inheritIO() // recopie les Entrées/Sortie sur la console du prog Java
    			.start();
    		process.waitFor();
    a++
    On est toujours en 1.6 chez moi. Obsolète mais pas trop comme il y a ProcessBuilder. Mais un peu trop car pas d' inheritIO.
    Mais je suppose que ça doit être faisable quand même.

    Du coup faut parler à qui pour mettre à jour les tutos

    Merci pour les suggestions

  8. #8
    Nouveau membre du Club
    Homme Profil pro
    Développeur Java
    Inscrit en
    Février 2015
    Messages
    30
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Vienne (Limousin)

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Février 2015
    Messages : 30
    Points : 27
    Points
    27
    Par défaut
    Me revoilà... évidemment on pense qu'on va avoir le temps de faire des choses et au final ça ne se passe jamais comme prévu

    Alors joel.drigo j'ai testé ton exemple avec 1.7, c'est vrai que c'est beaucoup plus simple a écrire.
    Mais tu utilises inheritIO comme avait proposé adiGuba sauf que je suis en 1.6.

    En ce qui concerne mon problème initial, j'ai créé un exe qui affiche "hello world" toutes les 2 secondes 10 fois.
    Et je récupère bien chaque ligne au moment ou elle est écrite. Du coup je vais chercher coté exe.

    Par contre j'ai essayé de faire marcher ta démo en gardant la gestion des flux comme je l'avais faite dans mon premier message.

    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
     
    public class Demo
    {
    	public static void main(final String[] args)
    	{
    	        final String[] command = { "java", "testappexterne.AppliExterne" };
    		final ProcessBuilder processBuilder = new ProcessBuilder(command).directory(new File("bin"));
    		try
    		{
    			final Process process = processBuilder.start();
     
                            // Fermeture stdin
    			process.getOutputStream().close();
     
                            // Fermeture stderr
    			process.getErrorStream().close();
     
                            // Lecture stdout
    			new Thread(new DisplayStream(process.getInputStream())).start();
     
    			process.waitFor();
    		}
    		catch (final IOException e)
    		{
    			e.printStackTrace();
    		}
    		catch (final InterruptedException e)
    		{
    		}
    		System.out.println("Fin du programme");
    	}
    }
     
     
    final class DisplayStream implements Runnable
    {
    	private final InputStream stream;
     
    	DisplayStream(final InputStream _stream)
    	{
    		stream = _stream;
    	}
     
    	private BufferedReader getBufferedReader(final InputStream is)
    	{
    		return new BufferedReader(new InputStreamReader(is));
    	}
     
    	@Override
    	public void run()
    	{
    		final BufferedReader br = getBufferedReader(stream);
    		String line = "";
    		try
    		{
    			while ((line = br.readLine()) != null)
    			{
    				System.out.println(line);
    			}
    		}
    		catch (final IOException e)
    		{
    			Debug.logEvent(EventType.ERROR, e);
    		}
    		finally
    		{
    			StreamUtils.closeQuietly(stream);
    		}
    	}
    }
     
    public class AppliExterne
    {
    	public static void main(final String[] args)
    	{
    		System.out.println("Entrer un mot (ou chaine vide pour arrêter).");
    		final Scanner scanner = new Scanner(System.in);
    		for (String input = scanner.nextLine(); !input.isEmpty(); input = scanner.nextLine())
    		{
    			System.out.println("Vous avez saisi : " + input);
    			System.out.println("Entrer un mot (ou chaine vide pour arrêter)");
    		}
    		System.out.println("Fin.");
    	}
    }
    Et le programme se termine immédiatement, je n'ai pas le temps taper de mot. Comme si le waitfor ne servait à rien. Alors que ça fonctionne bien avec ineritIO.
    J'ai testé en utilisant les deux JRE c'est pareil.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Entrer un mot (ou chaine vide pour arr�ter) // Ecrit par l'app externe
    Fin du programme // Ecrit par le main
    Et au lieu de AppliExterne j'ai utilisé mon exe Helloworld * 10 et ça récupère bien les lignes.

  9. #9
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par Dia972 Voir le message
    Et le programme se termine immédiatement, je n'ai pas le temps taper de mot. Comme si le waitfor ne servait à rien. Alors que ça fonctionne bien avec ineritIO.
    J'ai testé en utilisant les deux JRE c'est pareil.
    Ton programme ferme les flux : donc l'autre qui essaye d'écrire dedans, ou le tiens qui essaye de lire se tape une exception parce qu'il essaye de lire ou d'écrire dans un flux fermé.

  10. #10
    Nouveau membre du Club
    Homme Profil pro
    Développeur Java
    Inscrit en
    Février 2015
    Messages
    30
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Vienne (Limousin)

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Février 2015
    Messages : 30
    Points : 27
    Points
    27
    Par défaut
    Et bah oui

    Bon ben je passe en résolu. Merci à toi joel.drigo et à toi adiGuba pour ton tuto

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

Discussions similaires

  1. gestion des flux
    Par vamos dans le forum Développement
    Réponses: 4
    Dernier message: 19/04/2010, 08h10
  2. Gestion des flux
    Par DooSquare dans le forum Sécurité
    Réponses: 0
    Dernier message: 29/07/2008, 08h30
  3. [Process] Gestion des flux
    Par diamonds dans le forum API standards et tierces
    Réponses: 16
    Dernier message: 30/03/2007, 16h43
  4. Gestion des flux de matières dans 1 atelier
    Par ptit_bleu dans le forum Schéma
    Réponses: 4
    Dernier message: 23/02/2007, 10h55
  5. Gestion des flux de données
    Par pdiaz dans le forum Oracle
    Réponses: 2
    Dernier message: 10/01/2007, 17h30

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