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 :

Process OutputStream Buffered?


Sujet :

Entrée/Sortie Java

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Mai 2008
    Messages : 11
    Points : 8
    Points
    8
    Par défaut Process OutputStream Buffered?
    Hi all,

    Je suis en train de travailler sur librairie de scripting pour Scala (http://www.scala-lang.org/). Pour ceux qui ne connaissent pas ce language, Scala est un language fonctionnel et OO qui utilise directement java. Il est donc possible d'écrire du Java avec du scala (d'où ma présence sur ce forum ).

    Je dois implémenter les opérations standard du shell (>,|,<,||,&&,...) afin de pouvoir utiliser Scala comme un language de scripting. J'utilise donc les classes ProcessBuilder et Process.

    Voilà pour le background.

    J'ai cependant un problème relativement coriace pour les pipes : il faut rediriger la sortie du premier process vers l'entrée du deuxième process. Ca marche nickel pour un premier process qui se termine, car je peux fermer l'outputstream du deuxième. Cependant, pour un premier process qui ne s'arrête jamais (typiquement, "tail -f file"), je ne peux pas fermer l'outputStream du deuxième (évidemment). J'essaie vainement de flusher l'outputstream, mais le deuxième process reçoit les données en entrée que lorsqu'une certaine quantité y a été écrite (environ 900bytes). Ceci n'est pas acceptable pour un progamme du type "tail -f file" qui renvoit que très peu de données.

    Voici un example de code (en Java) qui caractérise bien ce que j'essaie de faire :

    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
     
                proc1 = Runtime.getRuntime().exec("tail -f file");
                proc2 = Runtime.getRuntime().exec("grep pattern");
                br1 = new BufferedInputStream(proc1.getInputStream());
                br2 = new BufferedInputStream(proc2.getInputStream());
                out = proc2.getOutputStream();
     
     
                // Thread for reading output of process2
                new Thread (){
                    public void run () {
                        int read = -1;
                        byte[] buffer = new byte[1];
                        try {
                            while ((read = br2.read(buffer)) != -1) {
                                System.out.write(buffer, 0, read);
                                System.out.flush(); 
                            }
                             br2.close();
                        } catch (IOException ex) {
                             // Handle exception
                        }
                    }
                }.start();
     
                byte[] buffer = new byte[1]; // Should be greater (just for demo here)
                int read = -1;
                // Read output of process1 and feed input of process2 with
                while ((read = br1.read(buffer)) != -1) {
                    out.write(buffer,0,read);
                    out.flush(); //Should flush, wtf??
                }
                out.close();
                br1.close();
                proc1.waitFor();
                proc2.waitFor();
    Ca sent furieusement l'outputStream bufferisé. Pour m'en assurer, j'ai été voir l'implémentation directement dans le source code java, et effectivement, on reçoit bien un BufferedOutputStream lorsque l'on appelle getOutputStream d'un Process. Alors pourquoi ça ne flush pas correctement? Ai-je oublié quelque chose de fondamental? Est-ce normal?

    Merci pour votre aide :-)

    System :
    java version "1.6.0_06"
    Java(TM) SE Runtime Environment (build 1.6.0_06-b02)
    Java HotSpot(TM) 64-Bit Server VM (build 10.0-b22, mixed mode)
    Linux 2.6.24-gentoo-r7 x86_64 Intel(R) Core(TM)2 Duo CPU E6750 @ 2.66GHz GenuineIntel GNU/Linux

    Alexandre Roux

  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,



    Les flux entres process sont en effet bufférisé... et je ne sais pas s'il est possible de remédier à cela.


    Mais as-tu réellement besoin de passer par Java ? Il serait plus simple d'utiliser le shell pour tout cela :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    	String[] command = {"/sin/sh", "-c", "tail -f file | grep pattern" };
    	Process proc1 = Runtime.getRuntime().exec(command);
     
    	// Traitements des E/S

    • Fermes les flux que tu n'utilises pas, car cela pourrait générer des interblocages.
    • Evites les bloc catch vide ! C'est le meilleur moyen de passer des heures à chercher une erreur mystérieuse qu'on aurait résolu en 2 temps 3 mouvements avec un joli stacktrace
    • Utilises des try/finally pour refermer tes flux.


    Plus d'info :



    a++

  3. #3
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Mai 2008
    Messages : 11
    Points : 8
    Points
    8
    Par défaut
    Citation Envoyé par adiGuba Voir le message
    Salut,



    Les flux entres process sont en effet bufférisé... et je ne sais pas s'il est possible de remédier à cela.
    Aïe...ce que je comprends pas c'est pourquoi la méthode flush ne flush par correctement le buffer...il y a plusieurs niveaux de buffer?
    Pour moi ceci s'apparente plutôt à un bug, ou à une choix d'implémentation peu judicieux. Je pense qu'il est légitime de vouloir passer peu de données à un process sans forcément fermer l'outputStream (d'où l'existence d'une méthode flush).

    Citation Envoyé par adiGuba Voir le message
    Mais as-tu réellement besoin de passer par Java ? Il serait plus simple d'utiliser le shell pour tout cela :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    	String[] command = {"/sin/sh", "-c", "tail -f file | grep pattern" };
    	Process proc1 = Runtime.getRuntime().exec(command);
     
    	// Traitements des E/S
    Il faut que ce soit totalement indépendant de la platforme, c'est pour ça que je voulais le faire directement. Mais comme je l'ai dis, ça marche très bien pour programme qui se termine. Pour, par exemple, "cat file | grep pattern" ça marche parfaitement.

    Par exemple, il est possible d'écrire ceci en Scala grâce à ma librairie :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    "cat myFile" | "grep myPattern" ->- "file.txt"
    qui est l'équivalent de ceci en bash :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    cat myFile | grep myPattern > file.txt
    C'est serait vraiment moche (et pas du tout multiplatform) de générer une ligne de commande à balancer à sh...

    Enfin bon, si je trouve pas comment régler ce problème, je pourrais effectivement créer une méthode alternative de pipe qui lancera une instance de shell comme tu me l'as suggéré.

    Citation Envoyé par adiGuba Voir le message
    • Fermes les flux que tu n'utilises pas, car cela pourrait générer des interblocages.
    • Evites les bloc catch vide ! C'est le meilleur moyen de passer des heures à chercher une erreur mystérieuse qu'on aurait résolu en 2 temps 3 mouvements avec un joli stacktrace
    • Utilises des try/finally pour refermer tes flux.
    Oui oui je le fais correctement dans ma library; j'ai posté ce code, raccourci et minimaliste, en java juste pour que vous ayez une idée de ce que je fais en scala (Parce que mettre du code Scala...enfin la syntax est très proche mais bon...)...

    Alexandre Roux

  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
    Citation Envoyé par alexroux Voir le message
    Aïe...ce que je comprends pas c'est pourquoi la méthode flush ne flush par correctement le buffer...il y a plusieurs niveaux de buffer?
    Je pense oui !
    Le flush du BufferedOutputStream fonctionne correctement, et je viens aussi d'essayer en passant outre le buffered via la reflection, mais le résultat est le même...



    Sinon pour tout le reste je suis plutôt d'accord avec toi (désolé mais j'ai tendance à chercher à simplifier le problème car je vois souvent des messages avec des problèmes complexes alors qu'il existe des solutions bien plus simple), mais je ne vois pas vraiment de solution au problème

    a++

  5. #5
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Mai 2008
    Messages : 11
    Points : 8
    Points
    8
    Par défaut
    Citation Envoyé par adiGuba Voir le message
    Je pense oui !
    Le flush du BufferedOutputStream fonctionne correctement, et je viens aussi d'essayer en passant outre le buffered via la reflection, mais le résultat est le même...
    Oki, je me disais bien que le BufferedOutputStream ne pouvait que fonctionner correctement, et que ça venait de plus bas...

    Citation Envoyé par adiGuba Voir le message
    Sinon pour tout le reste je suis plutôt d'accord avec toi (désolé mais j'ai tendance à chercher à simplifier le problème car je vois souvent des messages avec des problèmes complexes alors qu'il existe des solutions bien plus simple), mais je ne vois pas vraiment de solution au problème

    a++
    Oki, Merci . Si je trouve pas de solution, je pense poster un bug report sur le site de Sun, on verra bien En attendant, je laisse le thread ouvert, on sait jamais...

    A++

    Alexandre Roux

  6. #6
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Mai 2008
    Messages : 11
    Points : 8
    Points
    8
    Par défaut
    En fait, la solution alternative ( faire sh -c "tail -f file | grep pattern") ne fonctionne pas mieux..y a exactement le même problème. Autant pour le problème original j'avais plus ou moins une explication, autant là je vois vraiment pas pourquoi...

Discussions similaires

  1. stencil buffer
    Par patapetz dans le forum OpenGL
    Réponses: 6
    Dernier message: 26/02/2004, 17h23
  2. A propos depth buffer
    Par j.yves dans le forum DirectX
    Réponses: 1
    Dernier message: 03/12/2002, 00h41
  3. Vider le buffer du clavier
    Par flavien tetart dans le forum x86 16-bits
    Réponses: 2
    Dernier message: 12/07/2002, 08h35
  4. Affichage en passant par un buffer...
    Par Sirotilc dans le forum MFC
    Réponses: 5
    Dernier message: 27/05/2002, 21h00
  5. Alpha blending et Z-buffer directx 8
    Par Cesar4 dans le forum DirectX
    Réponses: 1
    Dernier message: 23/05/2002, 12h58

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