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

C++ Discussion :

Redirection de flux standard vers des fichiers


Sujet :

C++

  1. #1
    Membre régulier Avatar de raoulchatigre
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    99
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Bas Rhin (Alsace)

    Informations forums :
    Inscription : Mars 2004
    Messages : 99
    Points : 87
    Points
    87
    Par défaut Redirection de flux standard vers des fichiers
    Bonjour à tous,

    Je développe actuellement une application en C++, j'ai intégré une librairie de gestion des log (log4cpp) très pratique : j'en suis ravi.
    Cependant j'utilise encore pas mal de librairies un peu obsolètes qui sont remplies de "cout" et "cerr". De plus j'utilise parfois (et c'est mal !) l'appel system().

    Bref, afin de garder des logs propres et de ne pas éparpiller mes informations, j'ai cherché à réunir tous les flux sur les mêmes fichiers : appelons-les cout.std et cerr.log

    Pour réunir tous mes flux, je n'ai trouvé d'autre solution qu'utiliser la primitive C freopen()

    j'ai donc :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
        FILE *stdoutToStdStream = freopen( "cout.std", "a+", stdout );
        FILE *stderrToStdStream = freopen( "cout.std", "a+", stderr );
        FILE *stderrToLogStream = freopen( "cerr.log", "a+", stderr );
    Remarquez que le fichier cout.std contient tout (stdout+stderr)
    tandis que le fichier cerr.log ne contient que les erreurs critiques.
    C'est d'ailleurs ainsi que j'ai configuré log4cpp. Ainsi cela me permet d'être alerté par la présence d'info dans la log et d'étudier le problème en détail avec cout.std.

    Le problème qui se pose à moi, c'est que le deuxième appel qui concerne le flux 'stderr' semble annuler le premier.

    D'ailleurs comme le dis mon copain "man freopen" :

    FILE *freopen(const char *restrict filename, const char *restrict mode, FILE *restrict stream);
    The freopen() function shall first attempt to flush the stream and close any file descriptor associated with stream.
    Alors voilà, je bute...
    Je me demandais si des fois un autre appel n'existe pas...

    Merci de votre aide.

  2. #2
    Membre expérimenté

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 294
    Détails du profil
    Informations personnelles :
    Localisation : Royaume-Uni

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 294
    Points : 1 543
    Points
    1 543
    Par défaut
    Salut,

    Tu peux aussi utiliser la méthode rdbuf de std::cout (et/ou std::cerr) pour parvenir au même résultat :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    std::ofstream file( "cout.std" );
    std::cout.rdbuf( file.rdbuf() );
    Il vaut mieux remettre l'ancien buffer à la fin, c'est plus propre (sauvegarder le retour de std::cout.rdbuf() avant et le remettre après).

    MAT.

  3. #3
    Alp
    Alp est déconnecté
    Expert éminent sénior

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Points : 11 861
    Points
    11 861
    Par défaut
    Avec le code de Mat.M, lorsque tu feras
    la chaîne sera envoyée dans le fichier cout.std.

    Je pense que c'est le plus simple et le plus pratique pour toi.

  4. #4
    Membre régulier Avatar de raoulchatigre
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    99
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Bas Rhin (Alsace)

    Informations forums :
    Inscription : Mars 2004
    Messages : 99
    Points : 87
    Points
    87
    Par défaut
    Bonjour, merci pour l'aide !

    Okay j'ai suivi votre idée et j'ai écris ça :
    (j'ai changé un peu les noms de fichiers, désolé)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
        // Redirection de cout+cerr vers le fichier Std
        std::ofstream coutToStdFile( "cout.Std" );
        std::cout.rdbuf( coutToStdFile.rdbuf() );
        std::ofstream cerrToStdFile( "cout.Std" );
        std::cerr.rdbuf( cerrToStdFile.rdbuf() );
     
        // Redirection de cerr vers le fichier Log
        std::ofstream logFile( "cerr.Log" );
        std::cerr.rdbuf( logFile.rdbuf() );
     
        // ... mon programme
     
       // ... ensuite on remet les flux comme au départ.
    Je viens de tester et le problème est toujours le même...
    Mon fichier std ne contient que le flux cout et pas le flux cerr...
    J'ai l'impression qu'un flux ne peut avoir qu'une entrée et qu'une sortie, je me trompe ?

    Cordialement,

  5. #5
    Membre expérimenté

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 294
    Détails du profil
    Informations personnelles :
    Localisation : Royaume-Uni

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 294
    Points : 1 543
    Points
    1 543
    Par défaut
    Citation Envoyé par raoulchatigre Voir le message
    J'ai l'impression qu'un flux ne peut avoir qu'une entrée et qu'une sortie, je me trompe ?
    Un flux écrit dans un seul buffer oui.
    Par contre tu peux écrire une implémentation de std::basic_streambuf composite qui dédouble tous les appels pour rappeler sur plusieurs buffers à la fois.
    Tu le construits avec les 2 buffers renvoyés par std::cout.rdbuf() et std::cerr.rdbuf() et tu l'assignes comme buffer du std::ofstream.
    Si mes souvenirs sont bons le plus simple est de réimplémenter la méthode overflow de std::streambuf.

    Un truc genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class composite_buffer : public std::streambuf
    {
      ...
    protected:
      virtual int_type overflow( int_type c )
      {
        int_type c1 = buffer1.overflow( c );
        int_type c2 = buffer2.overflow( c );
        if( c1 == EOF || c2 == EOF )
          return EOF;
        return c1;
      }
    };
    Bon c'est l'idée mais c'est sans doute au moins partiellement faux et au mieux à creuser un peu...

    MAT.

  6. #6
    Membre expérimenté

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 294
    Détails du profil
    Informations personnelles :
    Localisation : Royaume-Uni

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 294
    Points : 1 543
    Points
    1 543
    Par défaut
    Citation Envoyé par Mat007 Voir le message
    Bon c'est l'idée mais c'est sans doute au moins partiellement faux et au mieux à creuser un peu...
    Surtout qu'en fait c'est l'inverse que tu veux faire toi, donc non rien, je vais juste aller reprendre un café et on en reparle après...

    MAT.

  7. #7
    Membre expérimenté

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 294
    Détails du profil
    Informations personnelles :
    Localisation : Royaume-Uni

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 294
    Points : 1 543
    Points
    1 543
    Par défaut
    Je ne sais pas si tu es un peu familier avec Boost.Test, mais il semble que ce test passe :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    BOOST_AUTO_TEST_CASE( RedirectionDeFlux )
    {
        std::stringstream os;
        std::streambuf* buf1 = std::cout.rdbuf();
        std::cout.rdbuf( os.rdbuf() );
        std::streambuf* buf2 = std::cerr.rdbuf();
        std::cerr.rdbuf( os.rdbuf() );
        std::cout << "cout";
        std::cerr << "cerr";
        std::cout.rdbuf( buf1 );
        std::cerr.rdbuf( buf2 );
        BOOST_CHECK_EQUAL( "coutcerr", os.str() );
    }
    Donc la méthode fonctionne pour envoyer plusieurs flux dans un seul flux.
    Pour faire l'opération inverse (dédoubler des flux), je pense qu'il n'y a pas le choix que d'utiliser une variante de celle que j'ai décrite avant mon café.

    MAT.

  8. #8
    Membre régulier Avatar de raoulchatigre
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    99
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Bas Rhin (Alsace)

    Informations forums :
    Inscription : Mars 2004
    Messages : 99
    Points : 87
    Points
    87
    Par défaut
    Mon cher Mat007,
    connais-tu la programmation par contrainte ?
    laisse moi t'initier à cet art délicieux :
    tu dois arriver a coder un programme SANS utiliser certaines bilbiotèques (comme Boost par exemple) et ce pas juste parce que ton boss a dis "NON", mais parce que la contrainte dynamise l'art, tu vois ?
    C'est un jeu super rigolo auquel je m'addonne en permanence mais qui a un prix : mes neurones !

    Bref j'arrête le cynisme, je te remercie vraiment de ces informations c'est fort intéressant vu que je suis un peu nul en flux. Mais je crois que je vais laisser là mon idée de croiser les flux et poser une belle prose au milieu du code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    //todo : faire ce qui doit être fait quand on pourra le faire

    ps : comme ils disent dans GhostBusters : c'est pas bien de croiser les flux !

  9. #9
    Membre expérimenté

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 294
    Détails du profil
    Informations personnelles :
    Localisation : Royaume-Uni

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 294
    Points : 1 543
    Points
    1 543
    Par défaut
    Citation Envoyé par raoulchatigre Voir le message
    (...) SANS utiliser certaines bilbiotèques (comme Boost par exemple) (...)
    C'est juste pour écrire le test unitaire que j'ai mis du boost, mais le code testé en lui-même ne s'en sert pas.

    Bon courage avec ton chef !

    MAT.

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

Discussions similaires

  1. Redirection standard vers plusieurs fichiers
    Par AralVor dans le forum Linux
    Réponses: 4
    Dernier message: 13/06/2009, 10h33
  2. renvoyer la sortie standard vers un fichier
    Par batotoba dans le forum ANT
    Réponses: 1
    Dernier message: 05/09/2006, 10h06
  3. Redirection d'un select vers un fichier
    Par Perseide dans le forum DB2
    Réponses: 3
    Dernier message: 19/07/2006, 21h49
  4. Réponses: 2
    Dernier message: 25/06/2006, 20h06
  5. |VB6] Comment Lister les liens vers des fichiers d'une page web
    Par Mayti4 dans le forum VB 6 et antérieur
    Réponses: 8
    Dernier message: 18/01/2005, 18h17

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