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

SL & STL C++ Discussion :

Questions sur ofstream et création d'une instance de classe


Sujet :

SL & STL C++

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    120
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 120
    Points : 58
    Points
    58
    Par défaut Questions sur ofstream et création d'une instance de classe
    Bonjour à tous,

    Voilà je commence le C++ et j'ai essayé de faire un petit programme qui écrit du texte dans un fichier. Ce programme est le suivant :
    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
    #include <iostream>
    #include <fstream> 
    #include <stdio.h>
    #include <windows.h>
     
    using namespace std;
     
    class TestFichier {
     
    	string nomFichier;
    	ofstream fichier;
     
    	public :
    		TestFichier();
    		void ajoutTexte(string texte);
    		void finFichier();
    };
     
    TestFichier::TestFichier(){
    	nomFichier = "fichier.txt";
     
    	ofstream fichier(nomFichier.c_str(), ios::trunc);
     
    	if (!fichier){
      		cerr << "Erreur de création du fichier" << endl;
      		exit(1);
    	}
     
    	SYSTEMTIME dateSysteme;
            GetSystemTime(&dateSysteme);
     
    	fichier << "--------------------------------------------" << endl;
    	fichier << "Fichier enregistré le ";
    	fichier << dateSysteme.wDay << "/" << dateSysteme.wMonth << "/" << dateSysteme.wYear << " à " << dateSysteme.wHour+1 << ":" << dateSysteme.wMinute << ":" << dateSysteme.wSecond << endl;
    	fichier << "--------------------------------------------" << endl;
    }
     
    void TestFichier::ajoutTexte(string texte){	
    	fichier << "Ajout de texte" << endl;
    	fichier << texte << endl;
    }
     
    void TestFichier::finFichier(){
    	fichier.close();
    }
     
    int main(){
     
    	TestFichier *test = new TestFichier();
     
    	test->ajoutTexte("Test");
     
    	test->finFichier();
     
    	return 0;
    }
    Je rencontre un problème (ou une erreur de ma part) car pour que la fonction ajoutTexte() marche je suis obligé de rajouter en début de cette fonction l'instruction suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ofstream fichier(nomFichier.c_str(), ios::app);
    Ou il faut que je mette à la place de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ofstream fichier(nomFichier.c_str(), ios::trunc);
    dans le constructeur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ofstream fichier(nomFichier.c_str(), ios::in|ios::out);
    Je ne sais pas si c'est normale ou que j'ai fait une erreur.

    Sinon, j'ai rencontré un autre problème pour créér une instance de cette classe. J'avais essayé de le faire de cette manière :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    int main(){
     
    	TestFichier test();
     
    	test.ajoutTexte("Test");
     
    	test.finFichier();
     
    	return 0;
    }
    Mais ça ne marche pas j'ai l'erreur suivante :
    testFichier.cc: In function `int main()':
    testFichier.cc:53: error: request for member `ajoutTexte' in `test', which is of non-class type `TestFichier ()()'
    testFichier.cc:55: error: request for member `finFichier' in `test', which is of non-class type `TestFichier ()()' .
    Si quelqu'un pouvait me donner quelques précisions sur pourquoi je suis obligé de passer par un pointeur : TestFichier *test = new TestFichier();, pour appeler les fonctions de la classe TestFichier. Ca serait sympa.

    Merci d'avance pour vos réponses

  2. #2
    Membre habitué
    Profil pro
    Étudiant
    Inscrit en
    Août 2005
    Messages
    161
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Maine et Loire (Pays de la Loire)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2005
    Messages : 161
    Points : 185
    Points
    185
    Par défaut
    Replace
    par

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    258
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France, Bas Rhin (Alsace)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 258
    Points : 307
    Points
    307
    Par défaut
    Le bout de code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    TestFichier test();
    est vu comme la déclaration d'une fonction nommée test, ne prenant pas de paramètres et renvoyant un objet de type TestFichier. cf. http://www.parashift.com/c++-faq-lit....html#faq-10.2

    Ton premier problème est dû au fait que tu déclares un objet de type ofstream nommé fichier dans le constructeur, et qui masque localement la donnée membre. À la fin du constructeur, la variable locale à celui-ci est détruite, et la variable membre, qui n'a jamais été modifiée, continue à indiquer un fichier fermé.

  4. #4
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,

    D'abord, il faut savoir que l' *idéal*, ca reste toujours de ne faire usage du disque dur que quand tu n'a pas (plus) le choix:
    • Quand il faut bien commencer par lire les informations que contient le fichier
    • Quand il faut bien s'arranger pour faire correspondre les changemements apportés au fichier (avant de quitter)


    Entre les deux, il est largement recommandé de travailler plutôt avec une représentation mémoire du fichier...

    Les raisons sont simples à comprendre:
    • Tant que le fichier est ouvert, il est "verrouillé" pour les autres applications qui devraient y accéder en lecture
    • Les temps d'acces au disque dur -et, de manière générale, à tous les supports, amovibles ou non- sont tres largement supérieurs à ceux de la mémoire RAM


    Enfin, il *peut*, selon l'usage de la classe que tu prévois, être intéressant de maintenir en mémoire l'ensemble des informations que tu affiche dans le constructeur, de manière à pouvoir les afficher à un autre moment

    Sans oublier, enfin, que, de fait, tu crées un ofstream local à ton constructeur qui cache temporairement celui de la classe, ainsi que l'a signalé roulious...

    La classe que je te conseillerais d'utiliser pour prendre toutes ces remarques en compte serait du genre de
    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
     
    class TestFichier
    {
        private:
            //les membres privés de la classe
            std::string fichier;//le nom du fichier
            std::vector<std::string> chaines;//le contenu du fichier
            //éventuellement, quelques infos utiles
            unsigned int tailledepart;
            SYSTEMTIME datesystem;//la date de dernière modification
            //quelques fonctions privées qui permettent la gestion interne
            void ReadFile();// DD->RAM
            // celle-ci pourrait très bien etre publique, afin de permettre 
            // l'enregistrement en cours de travail et éviter de tout perdre suite
            // à une panne de courent, par exemple ;)
            void WriteFile();// RAM->DD
        public:
            TestFichier(const std::string&);
            ~TestFichier();
            void AjoutTest(const std::string &);
            void PrintLastTime();//affiche la date de la dernière modification ;)
    };
    Dans le constructeur, on assignerait la valeur à fichier, puis on appellerait la fonction ReadFile()

    Dans le destructeur, on appelerait la fonction WriteFile() pour mettre le fichier à jour...

    Voici l'implémentation qui serait faite:
    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
     
    TestFichier::TestFichier(const std::string& filename):fichier(filename)
    {
        ReadFile();
    }
    TestFichier::~TestFichier()
    {
        WriteFile();
        //par sécurité, on vide les chaines
        chaines.clear();
    }
    void TestFichier::ReadFile()
    {
        // on va travailler avec une variable de type fichier locale à la fonction
        // le résultat est que le fichier est libre une fois que l'on a quitté la
        // fonction
        std::ifstream ifs(filename.c_str())
        //et il nous faudra une chaine temporaire
        std::string ligne;
        //on lit le fichier ligne par ligne et on rajoute chaque ligne au vecteur
        while( std::getline(ifs,ligne))
        {
            chaines.push_back(ligne);
        }
        // si on les a déclarés, on initialise le nombre de ligne et la date de
        // modification du fichier
        tailledepart=chaines.size();
        GetSystemTime(&dateSysteme);
    }
    L'écriture du fichier peut etre envisagée de deux manières:
    • Soit, tu écrase l'ancien fichier avec un nouveau
    • Soit, tu concatène le contenu de l'ancien avec ce qui a été rajouté (dans ce cas, tailledepart devient utile )


    Dans le premier cas, c'est relativement simple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    void TestFichier::WriteFile()
    {
        //on ouvre le fichier en écriture
        std::ofstream ofs(fichier.c_str())
        //et on écrit l'ensemble des chaines qui se trouvent dans le vecteur
        for(unsinged int i=0;i<chaines.size();i++)
        {
            ofs<<chaine[i]<<std::endl;
        }
        //on peut mettre datesysteme à jour ;)
    }
    Dans le deuxième cas, c'est à peine plus compliqué: on n'écrit les lignes qu'à partir de tailledepart:
    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
     
    void TestFichier::WriteFile()
    {
        //on ouvre le fichier en éciture, mais en concaténation
        std::ofstream ofs(fichier.c_str(),std::ios::app);
        //si tu veux, tu peux rajouter une ligne signalant l'ajout ;)
        ofs<<"-------------------------Rajout apres ce point---------------"
           <<std::endl;
        //puis on effectue la boucle
        for(unsigned int i=tailledepart;i<chaines.size();i++)
        {
             ofs<<chaines[i]<<std::endl;
        }
        //tu peux mettre datesytem à jour ;)
    }
    Oupppsss... et j'allais oubliler l'implémentation de AjoutTest()... (PrintLastTime ne devrait pas poser problème )
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    void TestFichier::AjoutTest(const std::string& toadd)
    {
        chaine.push_back(toadd);
    }
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  5. #5
    Membre du Club
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    120
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 120
    Points : 58
    Points
    58
    Par défaut
    Tout d'abord, merci à tous les trois (poof65, roulious, koala01) pour vos réponses.

    En fait je veux utiliser un fichier puisque j'ai un programme qui va lancer une simulation et je veux pouvoir enregistrer (donc sur fichier, DD) un bilan de cette simulation pour faire des statistiques dessus.
    Voilà, pourquoi j'ai besoin d'un fichier.
    Cette simulation dure un certain nombre de jours et il faut que j'enregistre dans le fichier le "mini-bilan" de chaque journée c'est pour ça que j'avais la fonction ajoutTexte() qui est appelée à chaque fois qu'une journée est fini.

  6. #6
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Mais, surtout si la simulation dure plusieurs jours (et c'est d'ailleurs déjà le cas si elle dure plus de quelques minutes), il devient donc réellement important de laisser le fichier accessible en dehors des périodes d'écriture...

    Dis toi bien que, si tu lance ta simulation lundi matin et qu'elle travaille pendant deux semaines, tu seras sans doute tenté d'observer les premières tendances qui auront été dégagées le lundi...

    Si ta simulation utilise en permanence le fichier, tu la lance le lundi (pour deux semaines), tu n'auras acces au fichier (pour faire les statistiques)... qu'une fois que toute la simulation sera finie... et que tu te "tourneras les pouces" pendant tout le temps qu'elle durera...

    C'est la raison pour laquelle je te conseille franchement de garder un "buffer" des informations "toutes chaudes" fournies par la simulation et de les enregistrer "par lots" à délais réguliers, dépendemment de la vitesse de traitement et des quantités d'informations maintenues...

    Tu peux, par exemple, estimer que ton application envoye chaque fois les résultat à FichierTexte, qu'il emmagasine, mettons, les résultats par 100 (ou par 1000 ou 10.000, selon la taille du résultat et la vitesse à laquelle ils arrive) et, quand il a un nombre donné de résultat, il les enregistre à la fin du fichier...

    De cette manière, il n'y aura que le "court" moment où l'enregistrement est effectué pendant lequel tu ne pourra pas accéder, ne serait-ce qu'en lecture, au fichier de résultats...

    Tu pourrais, tres bien envisager les choses ainsi:
    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
     
    class FileTest
    {
        private:
            std::vector<resultat> m_result; // ou resultat peut prendre la forme
                                           // qui te plait ;)
            //L'écriture du fichier est privée (appelée dans AjoutResultat)
            void FileWrite();
            //il faut quand meme garder le nom du fichier
            std::string filename;
        public:
            //le constructeur qui prend le nom du fichier de sauvegarde
            FileTest(const std::string&);
            //et le destructeur
            ~FileTest();
            // la fonction d'ajout d'un résultat
            void AddResult(const result&);
    };
    Le constructeur fait encore moins:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    FileTest::FileTest(const std::string& filename):m_filename(filename){}
    Le destructeur, lui, appelle toujours la dernière écriture
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    FileTest::~FileTest()
    {
        //il serait vraiment trop bete de perdre quelques résultats parce que
        //quelqu'un lit le fichier pendant la fin de la simulation
        while(m_result.size()!=0)
        {
             FileWrite();
        }
    }
    L'ajout de résultat se fait tel que je l'ai indiqué plus haut, mais on rajoute une petite option: si le nombre de résultats est supérieur (ici, à 100, mais tu peux l'adapter en conséquence), on provoque l'écriture des résultats...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    void FileTest::AddResult(const result& res)
    {
        m_result.push_back(res);
        if(m_result.size()>=100)
        {
            FileWrite();
        }
    }
    Lors de l'écriture du fichier, il faut etre prudent (des fois que tu sois justement occupé à lire les résultat quand la classe veut enregistrer des données)
    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
     
    void FileTest::FileWrite()
    {
        //on tente d'ouvrir le fichier en concaténation
        std::ofstream ofs(m_filename.c_str(),std::ios::app);
        //on vérifie que l'ouverture a réussi
        if(ofs.is_open())
        {
            // on peut tres bien indiquer quelques informations 
            // tiens, prenons l'heure présente
            time_t Temps;
            tm* temps_infos;
            time(&Temps);
            temps_infos=localtime(&Temps);
            ofs<<"-------ajout de "<<m_resutl<<" resultats le "<<
               <<temps_infos->tm_mday<<"/"<<temps_infos->tm_mon<<"/"
               <<temps_infos->tm_year
               <<" à " <<temps_infos->tm_hour
               <<":"<<temps_infos->tm_min
               <<"-----------------------------------"<<std::endl;
            //on écrit l'ensemble des réslutats sauvegardés
            for(unsigned int i=0;i<m_result.size();i++)
            {
                 ofs<<m_result[i]<<std::endl;
            }
            //si l'écriture a eu lieu, on peu vider le vecteur
            m_result.clear();
        }
    }
    Et l'utilisation globale serait du genre de
    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
     
    int main(int argc, char *argv[])
    {
       //on construit le FileTest au tout début
       FileTest saver("fichier.txt")
       //on rentre dans une boucle de simulation
       do
       {
            resultat result;
           //on calucle le réusltat
           // ...
          //et on le rajoute
          saver.AddResult(result);
       }while(/* à completer ;) */)
    }
    Tel que c'est présenté ici, les résutlats seront enregistrés par à peu pres 100...

    En effet, si le fichier n'est pas accessible, les résultats suivants seront rajoutés à la liste de ceux qui doivent etre enregistrés jusqu'à ce que le fichier devienne accessible
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  7. #7
    Membre du Club
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    120
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 120
    Points : 58
    Points
    58
    Par défaut
    Désolez koala01 je me suis mal exprimé .
    Quant je parle de simulation de plusieurs jours c'est moi qui la la lance et la fait "dérouler" dans mon programme pour qu'elle dure sur un nombre de jours avec une boucle (un for) tout simplement.
    Elle ne dure pas plusieurs jours rééls .

  8. #8
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Points : 4 625
    Points
    4 625
    Par défaut
    Citation Envoyé par koala01
    Salut,

    D'abord, il faut savoir que l' *idéal*, ca reste toujours de ne faire usage du disque dur que quand tu n'a pas (plus) le choix:
    • Quand il faut bien commencer par lire les informations que contient le fichier
    • Quand il faut bien s'arranger pour faire correspondre les changemements apportés au fichier (avant de quitter)
    Ça, ça dépend fortement de ce qu'on fait.
    Et c'est, dans de nombreux cas, l'inverse qu'il faut faire.
    Boost ftw

  9. #9
    Membre du Club
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    120
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 120
    Points : 58
    Points
    58
    Par défaut
    J'ai fait une nouvelle version de ma classe TestFichier.
    La voilà :
    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
    #include <iostream>
    #include <fstream> 
    #include <stdio.h>
    #include <windows.h>
     
    using namespace std;
     
    class TestFichier {
     
    	string nomFichier;
     
    	public :
    		TestFichier();
    		~TestFichier();
    		void ajoutTexte(string texte);
    		void finFichier();
    };
     
    TestFichier::TestFichier(){
    	nomFichier = "fichier.txt";
     
    	ofstream fichier(nomFichier.c_str(), ios::trunc);
     
    	if (!fichier || !fichier.is_open()){
      		cerr << "Erreur de création ou d'ouverture du fichier" << endl;
      		exit(1);
    	}
     
    	SYSTEMTIME dateSysteme;
            GetSystemTime(&dateSysteme);
     
    	fichier << "--------------------------------------------" << endl;
    	fichier << "Fichier enregistré le ";
    	fichier << dateSysteme.wDay << "/" << dateSysteme.wMonth << "/" << dateSysteme.wYear << " à " << dateSysteme.wHour+1 << ":" << dateSysteme.wMinute << ":" << dateSysteme.wSecond << endl;
    	fichier << "--------------------------------------------" << endl;
    }
     
    TestFichier::~TestFichier(){
    	ofstream fichier(nomFichierBilan.c_str(), ios::in);
    	fichier.close();
    }
     
    void TestFichier::ajoutTexte(string texte){
    	ofstream fichier(nomFichier.c_str(), ios::app);
     
    	if (!fichier || !fichier.is_open()){
      		cerr << "Erreur d'ouverture du fichier" << endl;
      		exit(1);
    	}
     
    	fichier << "Ajout de texte" << endl;
    	fichier << texte << endl;
    }
     
    void TestFichier::finFichier(){
    	ofstream fichier(nomFichierBilan.c_str(), ios::in);
    	fichier.close();
    }
     
    int main(){
    	TestFichier test;
     
    	test.ajoutTexte("Test");
     
    	test.finFichier();
     
    	return 0;
    }
    Je ne sais pas trop si c'est utile que je fasse appel à la fonction finFichier() puisque je ferme le fichier (je fais la même chose) dans le desctructeur.
    Si vous voyez d'autre problèmes ou incohérences dans mon code je suis preneur.

    Merci d'avance pour vos réponses

  10. #10
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Encore une fois, tu crée un ofstream local à ton constructeur...

    Une meme cause ayant toujours les memes effet, le std::ofstream ouvert dans ton constructeur est fermé une fois que celui-ci est quitté...et il n'est donc pas disponible lors des appel à tes fonctions d'écriture...

    En plus, dans le destructeur, tu fais de toutes façons appel à une variable qui n'existe pas... le compilateur ne devrait meme pas accepter la compilation.

    J'ai nommé:nomFichierBilan pour laquelle tu sembles croire qu'il s'agirait d'une chaine et que tu en demanderais la convertion en chaine de caractères "C style"...

    Enfin, qu'il s'agisse de "FinFichier" ou du destructeur, peux tu nous donner une idée du but recherché en:
    • ouvrant un fichier
    • fermant ce fichier directement apres


    Le tout, sans rien faire d'autre entre les deux

    Contrairement à la remarque de loufoque, le fichier que tu essaye d'utiliser est d'une utilisation fort proche de celle d'un "fichier de trace"...

    Comme je te l'ai indiqué plus haut, le constructeur peut tres bien se contenter de définir une variable "nom de fichier" (de type string) et ne l'ouvrir en ajout qu'au moment où ... il y a quelque chose à écrire dans le fichier...

    Les moments où il faut écrire quelque chose dans le fichier sont (de manière non exhaustive)
    • quand un résultat ou un nombre de résultat suffisant est obtenu
    • éventuellement au moment de cloturer l'application, s'il y a des résultats qui n'ont pas encore été sauvegardés


    Je t'ai fournis suffisemment de codes d'exemple, avec suffisemment de commentaires pour te permettre de faire quelque chose de cohérent et de robuste

    Simplement, tu ne sembles pas "percuter" sur ce que l'on appelle la "portée d'une variable" et, plus particulièrement, sur les variables que l'on appelle "locales" (ou "de portée locale")...

    A part te dire que
    dans une fonction, une variable n'existe qu'à partir du moment où elle est déclarée (ce qui se fait en donnant son type et son nom) et que jusqu'à ce qu'on atteinge l'accolade fermant le bloc dans lequel elle est déclarée
    la seule chose que je puisse faire, c'est un dernier exemple là dessus...
    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
     
    //ce qui precede mafonction() n'a rien à voir avec mafonction()
    void mafonction()//début de la fonction
    { // accolade ouvrante qui signale le début du "bloc d'instruction" de la 
      // fonction
        int entier;//entier existe ici et jusqu'à l'accolade fermante [1]
     
        if(untest)
        {
            char caractere;//caractère n'existe que dans le test
                           //(jusquà l'accolade [2]
           //..
        } [2]
        float reel;//reel n'existait pas avant, et existera à partir d'ici et jusqu'à[1]
        ...
    }[1]//la fonction fini ici
    //ce qui suit la fonction n'a rien à voir avec mafonction()
    Le cas particulier, c'est les classes et les strucutres...

    Une fonction qui est membre d'une classe ou d'une structure en C++ (en fait, il y a très peu de différence entre une struct et une classe en C++) connait l'ensemble des membre de la classe (de la structure)
    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
    struc mastru
    {
        int entier;
        char caractere;
        float reel;
        void mafonction1();
        void mafonction2();
        void mafonction3()
    // ma fonction1(), mafonction2() et mafonction3() connaissent toutes
    // les trois entier, reel et caractere parce qu'elles sont membre de la
    // meme classe/structure
    // mais si tu déclares un nouveau int entier dans une des fonctions, cette
    // nouvelle déclaration sera considérée comme locale à la fonction
    // et cachera le entier "membre de la strucutre"
    };
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  11. #11
    Membre du Club
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    120
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 120
    Points : 58
    Points
    58
    Par défaut
    Merci pour ta réponse koala01.
    J'avais compris et je savais la majorité de ce que tu expliques dans ton message.
    Ce que je ne vois pas c'est comment déclarer un ofstream en tant qu'attribut de la classe sans l'initialiser et pouvoir l'utiliser dans les autres fonctions.

    Sinon, dans mon exemple de main comme tu le dis :
    Enfin, qu'il s'agisse de "FinFichier" ou du destructeur, peux tu nous donner une idée du but recherché en:

    * ouvrant un fichier
    * fermant ce fichier directement apr
    .
    Mais j'aurais besoin dans mon programme d'ouvrir le fichier dès le début de la simulation et de le fermer à la fin.
    J'aurais plutôt quelque chose du style comme main :
    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
    int main(){
    	TestFichier test;
     
            // Lancement de la simulation
            for (x journées){
                     // Actions pour chaque journée simulée 
                     ...
     
                     // A chaque de fin de journée j'enregistre le bilan
    	         test.ajoutTexte("Test");
            }
     
    	test.finFichier();
     
    	return 0;
    }

  12. #12
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    e que je ne vois pas c'est comment déclarer un ofstream en tant qu'attribut de la classe sans l'initialiser et pouvoir l'utiliser dans les autres fonctions
    Si ton ofstream est déjà construit, il faut utiliser sa fonction membre open pour l'ouvrir (qui prend les mêmes paramètres que le constructeur).
    Tu n'es pas non plus obligé de l'ouvrir / fermer dans chaque fonction, tu peux très bien le garder ouvert tout le temps que ton instance vit.

  13. #13
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Non, pour un fichier "log", tu n'a aucun besoin d'ouvrir le fichier au début et de le fermer à la fin...

    Un fichier "log", ca se doit d'etre accessible par les gens tant qu'il n'y a pas d'opérations d'écriture... (et c'est quand meme fort proche de ce que tu dois faire)

    Donc:
    • Tu déclares le nom du fichier dans le constructeur et
      • tu ouvre le fichier en concaténation
      • tu écris l'information que tu veux écrire dedans dans la fonction d'ajout d'information
    • Si nécessaire, tu t'assure d'une dernière écriture dans le destructeur (ce pourrait, par exemple etre "autant de résultats réunis en tel temps le date")


    Ce qu'il te faut, c'est tout bete:
    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
    class FichierTest
    {
        public:
            //le constructeur qui donne juste le nom du fichier
            FichierTest(const std::string& filename):m_filename(filename){}
            //le destructeur qui ne fait rien
            ~FichierTest(){}
            //La fonction d'ajout d'informations (implémentée plus loin)
            void AddInfo(const type_d_information&);
        private:
            //le nom du fichier
            std::string m_filename;
            //interdiction de la recopie
            FichierTest(const FichierTest&);
    };
    L'implémentation de AddInfo étant
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    void FichierTest::AddInfo(const type_d_information& info)
    {
        //je ne sais pas quelles sont les informations que tu dois écrire,
        //remplace type_d_information par le type adéquat ;)
        //on ouvre le fichier en ajout à la fin
        std::ofstream ofs(m_filename.c_str(),std::ios::app);
        //écritrure des informations en elles meme
        ofs<<info.var1<<" "<<info.var2<<" "<<info.var3<<std::endl;
        //nota: tu pourrais aussi surcharger l'operateur << pour les info, si
        // utile ;)
    }
    et l'utilisation se fait sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    int main(int argc, char *argv[])
    {
        FichierTest fichier("essai.txt");
        for(unsigned int jour=0;jour<...;jour++)
        {
              type_d_information resultat;
             //tout ton calcul pour obtenir le résultat
             fichier.AddInfo(resultat);
        }
        return 0;
    }
    Point, barre...

    Il ne sert à rien de chercher la difficulté là où elle n'a pas lieu d'être...

    Et dans le cas qui nous intéresse, la difficulté, c'est de vouloir absolument que le fichier soit ouvert pendant tout le temps d'exécution de l'application...

    Bien sur, il y a parfaitement moyen d'y arriver... mais ce sera à terme bien plus embêtant pour toi de garder ce fichier ouvert plutot que de l'ouvrir chaque fois que tu as une entrée à y écrire...

    Ne serait-ce que, parce que si ton application doit fonctionner ne serait-ce que pendant 5 minutes, on peut raisonnablement penser que tu voudras t'assurer qu'elle fonctionne correctement (faire des "sondages express" des résultats déjà obtenus)...

    Si ton fichier est ouvert au début et fermé à la fin, ca te devient impossible...

    Et autre corrolaire, c'est que tu auras, par exemple, chaque fois prévu que tes résultats vont par 4 chiffres et... pas de bol, au milieu du fichier, tu obtiens un résultat à 5 ou à 10... qui décale entièrement la ligne correspondante...

    Comme je ne doute pas que tu aimes le travail bien fait, les fichiers avec des colones clairements bien alignées et que tu as le soucis du détail, les décalages présents ne seront pas à ton gout...

    Du coup, avec le fichier ouvert en début et fermé à la fin, tu devras attendre la fin de l'exécution l'application avant de t'en appercevoir, pour pouvoir modifier, peut etre deux mots de code, et tu devra te retaper l'ensemble de l'exécution...

    Alors qu'en laissant le fichier accessible, tu pourras regarder régulièrement la "bouille" fichier résultant, et décider de suspendre l'exécution à tout moment parce qu'on se trouve face à un problème d'allignement des cololnes... Ce qui, au total te fera sans doute gagner de précieuses minutes...
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  14. #14
    Membre du Club
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    120
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 120
    Points : 58
    Points
    58
    Par défaut
    Citation Envoyé par Laurent Gomila
    Si ton ofstream est déjà construit, il faut utiliser sa fonction membre open pour l'ouvrir (qui prend les mêmes paramètres que le constructeur).
    Tu n'es pas non plus obligé de l'ouvrir / fermer dans chaque fonction, tu peux très bien le garder ouvert tout le temps que ton instance vit.
    Tout simplement.
    Je ne sais pas pourquoi je cherchais quelque chose de plus compliqué merci bien Laurent Gomila.

    Meric beaucoup koala01 pour toutes tes réponses. Désolez de ne pas avoir "percurter" dès le dédut.
    Sinon, une dernière chose en fait mon fichier ne sera pas vraiment un fichier de log puisque à chaque simulation je l'écrase. Je n'ai pas le besoin de garder d'une exécution à l'autre les résultats trouvés.
    Sinon, j'ai testé pour une simulation "normale" (de 10 000 journées) l'exécution de mon programme dure pas plus de 10 secondes. Donc je ne crois pas avoir le temps pendant la simulation d'aller voir les résultats obtenues.
    Enfin, dans ton dernier message est-ce normal que tu ne ferme pas le fichier ?

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

Discussions similaires

  1. Création d'une instance (interface / class)
    Par vandeyy dans le forum Débuter avec Java
    Réponses: 2
    Dernier message: 17/03/2014, 18h47
  2. [Lazarus] [Linux] Erreur lors de la création d'une instance de classe héritée
    Par timmalos dans le forum Lazarus
    Réponses: 2
    Dernier message: 10/05/2011, 12h59
  3. Réponses: 4
    Dernier message: 27/12/2009, 14h25
  4. [WPF] Plantage lors de la création d'une instance de classe
    Par tomlev dans le forum Windows Presentation Foundation
    Réponses: 3
    Dernier message: 14/09/2007, 14h31
  5. Création d'une instance
    Par coco-sup dans le forum Oracle
    Réponses: 10
    Dernier message: 31/12/2005, 19h30

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