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 :

string Buffer = "";


Sujet :

C++

  1. #1
    Membre averti
    Inscrit en
    Juillet 2008
    Messages
    20
    Détails du profil
    Informations forums :
    Inscription : Juillet 2008
    Messages : 20
    Par défaut string Buffer = "";
    salut
    j'ai un fichier .csv qui contient 27000 ligne et je veux suprrimer les ligne 4,5,6
    ça fonction avec le code que j'ai mais ça prend presque 2min pour s'exécuté
    y'a t'il unmoyenne pour minimiser le temps de l'execution

    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
     
    #include <string> 
    #include <fstream> 
     
    void Erase_Line1(char* z, int Line_to_Erase) 
    { 
    std::string Buffer = ""; //Variable contenant le texte à réécrire dans le fichier 
    std::ifstream ReadFile( z); 
    if (ReadFile) //Si le fichier est trouvé 
    { 
    std::string line; 
    int Line = 0; 
    while ( std::getline( ReadFile, line ) ) //on parcours le fichier et on initialise line à la ligne actuelle 
    { 
    Line++; 
    if(Line != Line_to_Erase) //Si la ligne atteinte est différente de la ligne à supprimer... 
    Buffer += line + "\n"; //On ajoute le contenu de la ligne dans le contenu à réécrire 
    } 
    } 
    ReadFile.close(); //On ferme le fichier en lecture 
     
    std::ofstream WriteFile( z); //On ouvre ce même fichier en écriture 
    WriteFile << Buffer; //On écris le texte dedans 
    WriteFile.close(); //et on ferme le fichier 
    } 
     
    int main() 
    { 
    Erase_Line1("z.txt", 4); 
    Erase_Line1("z.txt", 4); 
    Erase_Line1("z.txt", 4); 
     
    return 0; 
    }

  2. #2
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,

    Selon la taille réelle du fichier (parce que, 27000 lignes, ca fait beaucoup, mais, encore faut il voir combien de caractères cela représente ), tu pourrais envisager de te baser sur l'entrée de la FAQ qui présente comment lire l'intégralité d'un fichier dans un buffer...

    Une fois cette opération effectuée, il deviendra relativement facile de faire le tri de ce que tu veux garder et de ce que tu veux virer à coup de find_first_of, ingore et autres substr
    L'idée pouvant se baser sur un algorithme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    POUR chaque ligne précédent celle que je veux retirer
       écrire la ligne dans le fichier de destination
    FIN POUR
    supprimer la ligne que je veux retirer
    SI Fin exécution
        ecrire ce qui reste du fichier
    FIN SI
    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

  3. #3
    Membre éprouvé Avatar de BainE
    Inscrit en
    Mai 2004
    Messages
    1 327
    Détails du profil
    Informations forums :
    Inscription : Mai 2004
    Messages : 1 327
    Par défaut
    Oui,

    ecrire a la volée chaque ligne lue qui doit etre dans le fichier destination/final.
    De mémoire quand tu fais un append sur string (ou un +=) il y a creation d une nouvelle string et recopie ce qui prend beaucoup de temps.

    sinon il doit exister la classe stringbuffer qui peut aussi reduire le temps d execution.

    [edit] bon y a pas stringbuffer en cpp, mais la concatenation de 27000 string me semble etre tres optimisable.

  4. #4
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    La classe std::string possède une fonction membre reserve.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  5. #5
    Membre éprouvé Avatar de BainE
    Inscrit en
    Mai 2004
    Messages
    1 327
    Détails du profil
    Informations forums :
    Inscription : Mai 2004
    Messages : 1 327
    Par défaut
    ca se fait de reserver, disons des lignes de 50 car en moyennes soit 1.35 Mega Windowsien

    [edit] d autant que après test ça ne fait rien gagner en temps. Ce serait la recopie de caractère qui prendrait tout ce temps

  6. #6
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 728
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 728
    Par défaut
    Déjà, il serait peut être sage de ne pas relire 3 fois le fichier:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    int main() 
    { 
         Erase_Line1("z.txt", 4); // 1 fois
         Erase_Line1("z.txt", 4); // 2 fois
         Erase_Line1("z.txt", 4); // 3 fois
     
          return 0; 
    }
    => plutôt que de passer un numéro de ligne, passer un vecteur de lignes rangées dans l'ordre croissant
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    int main() 
    { 
         int lines[] = { 4, 5, 6, 0 };
         Erase_Line1("z.txt", lines);
         return 0; 
    }
    Puis on modifie le code de Erase_Line1
    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
    void Erase_Line1(char* z, int* lines_to_erase)
    { 
          std::ifstream ReadFile(z); 
     
          if (ReadFile) //Si le fichier est trouvé 
          { 
               std::ofstream WriteFile (z+qqc);
     
               std::string line;
                int linenb = 0; 
                int erasing_line = *lines_to_erase;
    
                while (erasing_line != 0) {
                     while ( std::getline( ReadFile, line ) ) //on parcours le fichier et on initialise line à la ligne actuelle 
                     { 
                           linenb++;
                           if (linenb == erasing_line)
                                 break;
                           WriteFile << line << endl; // *fix* nl?
    
                     }
                lines_to_erase++;
                erasing_line = *lines_to_erase;
                } 
                // recopier la fin du fichier ? Ajouter un test sur eof?
                while ( std::getline( ReadFile, line ) ) //on parcours le fichier et on initialise line à la ligne actuelle 
                { 
                           WriteFile << line << endl; // *fix* nl?
                 } 
                ReadFile.close(); //On ferme le fichier en lecture  
                WriteFile.close(); //et on ferme le fichier 
           }
    }
    Je n'ai pas testé, mais ca donne l'idée.
    - W
    edit: j'avais oublié de "coller" la fin du fichier
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  7. #7
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Ceci dit, je me rend compte que tu va lire l'intégralité du fichier... à chaque fois que tu voudra supprimer une ligne...

    Au final, en voulant supprimer trois lignes, tu en arrive à devoir en lire ... 3*27000 = 78000 ...

    Dés lors, tu pourrais surement diviser le temps nécessaire par trois, simplement en lisant le fichier une bonne fois pour toute et en mettant les lignes lues dans un conteneur "qui va bien"

    Ainsi, bien que la suppression d'élément ne soit pas "forcément" le point fort de la classe vector, tu pourrais envisager un code proche 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
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    int main()
    {
        /* un conteneur pour les lignes du fichiers */
        std::vector<std::string> tab;
        /* ouvrons le fichier en lecture */
        std::ifstream ifs("lefichier.csv");
        /*une chaine de caractères temporaire pour la lecture */
        std::string str;
        /* tant que l'on arrive à lire une ligne, ajoutons la dans le tableau
         * prévu à cet effet 
         */
        while(std::getline(ifs, str))
            tab.push_back(str);
        /* comme nous voudrons réouvrir le fichier en écriture
         * autant le fermer correctement 
         */
        ifs.close();
        /* créons deux itérateur: le premier sur la première chaine à supprimer
         * le second sur la derniere
         */
        std::vector<std::string>::iterator beg=tab.begin()+3 ;// (1+3= ...4 ;) )
        std::vector<std::string>::iterator end= tab.begin()+5;//(1+5 = ...6 ;) )
        /* et supprimons supprimons les, ainsi que ce qui se trouve entre les deux
         */
        tab.erase(beg, end);
        /* il n'y a plus qu'à réécrire le fichier */
        std::ofstream ofs("lefichier.csv");
        for(size_t i=0;i<tab.size();++i)
            ofs<<tab[i];
        /* merci d'être passé */
        return 0;
    }
    A adapter éventuellement pour apporter plus de flexibilité et ou plus de sécurité

    [EDIT]grilled sur la remarque
    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

  8. #8
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 728
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 728
    Par défaut
    Désolé

    Pourquoi vouloir charger le contenu du fichier en mémoire alors qu'il "suffit" (a mon sens) de le ré-écrire sans les lignes que l'on souhaite supprimer?
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  9. #9
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par wiztricks Voir le message
    Désolé

    Pourquoi vouloir charger le contenu du fichier en mémoire alors qu'il "suffit" (a mon sens) de le ré-écrire sans les lignes que l'on souhaite supprimer?
    - W
    Pour la raison toute simple que, dans l'état actuel des choses, yanlou ne semble pas vouloir prévoir la suppresion de plusieurs ligne d'une seule traite (ce que fait pourtant mon code)...

    Dés lors, si pour chaque suppression de ligne, tu impose la lecture/réécriture complète du fichier en vue d'en supprimer la ligne souhaitée, cela devient vraiment masochiste (imagine le jour où il souhaitera supprimer 100 lignes disséminées dans son fichier )

    une alternative serait de prendre les numéros de lignes avant toute suppression dans un conteneur trié (std::set, pourquoi pas ) et de les supprimer à la volée lors de la copie du fichier.

    Comme tu le vois, il y a de nombreuses solutions, et, finalement, aucune n'est *forcément* mauvaise... du moment que l'on s'arrange pour ne lire/écrire qu'une seule fois le fichier
    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

  10. #10
    Membre émérite
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    1 064
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2005
    Messages : 1 064
    Par défaut
    Moi je me demande pourquoi charger inutilement beaucoup de données en mémoire, avec toute la gestion de buffer que ça impose, alors qu'on peut faire si simple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    void eraseLines(const std::string& file,const std::string& tmpfile,std::set<unsigned int> lines) {
    ifstream f(file.c_str());
    ofstream tmpf(tmpfile.c_str());
     
    while(...) {
       lire ligne
       si ligne pas dans lines
          tmpf << line << std::endl;
    }
    supprimer file
    renommer tmpfile en file
    }
    A noter que pour trouver un fichier temporaire, il existe une fonction en C standard (par contre elle ne peut pas réserver un fichier sur un disque donné, ce qui ralentirait cet algo, mieux vaut ajouter un suffixe au nom du fichier d'origine)
    On peut même faire générique en passant un foncteur au lieu d'en set, vector trié ou autre, comme ça on pourrait déterminer si une ligne reste ou pas avec d'autres critères que son numéro.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Comme je l'ai dit, il existe plusieurs possibilités, et il est même vraisemblable que je me dirige vers une solution comme la tienne (nos posts se sont croisés ), zach, pour autant que j'aie la certitude que l'application ne devra jamais faire autre chose que supprimer des lignes "inutiles"...

    L'avantage de la solution que j'ai présentée avant est qu'elle permet malgré tout de garder les données "sous la main" s'il advient que la suppression de lignes ne doit être qu'une des possibilités offertes par l'application
    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

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

Discussions similaires

  1. Erreur character string buffer too small
    Par uriel khaan dans le forum SQL
    Réponses: 2
    Dernier message: 21/03/2007, 17h24

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