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 :

Lire - Ecrire fichier


Sujet :

C++

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2009
    Messages
    18
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2009
    Messages : 18
    Par défaut Lire - Ecrire fichier
    Bonjour à tous,

    Débutant...Désolé

    J'ai un fichier texte qui peut atteindre près de 1 million de ligne. Ce fichier texte est lisible ligne par ligne (ifstream(getline...). Je cherche à modifier certaines lignes. Par modification j'entends ajout, modification, suppression de lignes ou de sous-chaines ou de caractères dans une ligne. Les lignes, sous-chaines ou caractères peuvent être situés n'importe où.
    J'arrive à ouvrir le fichier en lecture, modifier des lignes, mais les modifs ne sont pas sauvegardées (normal pas de ofstream). Comment enregistrer les modifs ?

    Mon code fait le travail (ici remplacement de virgule-espace-virgule par virgule) :

    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
    int main()
    {
        string const nomFichier("fichier.txt");
        fstream monFlux(nomFichier.c_str());
        if (monFlux)
        {
            string ligne;
            while (getline(monFlux, ligne))
            {
                    regex pattern { ", ," };
                    string target { ligne };
                    string replacement { "," };
                    string result = regex_replace(target, pattern, replacement);
                    cout << result << endl;
            }
            monFlux.close();
        }
        else
        {
            cout << "Erreur : Impossible d'ouvrir le fichier !" << endl;
        }
        return 0;
    }
    Le problème est dans la sortie cout de result

    Si quelqu'un pouvait éclairer ma vue basse...

    Merci

    P.

  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
    Citation Envoyé par Phicome Voir le message
    Bonjour à tous,

    Débutant...Désolé
    Tu n'as aucun besoin de t'excuser : ce n'est pas une tare, c'est juste un état qui ne durera sans doute pas

    Et on est tous passés par là

    Mais, pour répondre à ta question:

    Le gros problème, c'est que tu dois considérer que ton fichier est "gravé dans le marbre": une fois qu'une information a été écrite dans un fichier, tu peux y faire "quelques ajustements" comme remplacer un 'a' par un 'x' ou par un 'z', mais, dés qu'il s'agit de modifier la taille de l'information (en ajoutant ou en retirant des lettres), tu n'as pas d'autre choix que de "briser la pierre", et de recommencer.

    De plus, il y a toute une série de raisons qui font que l'on évitera autant que possible de travailler directement sur le fichier, dont la principale est que l'accès aux données qui se trouvent sur un disque dur est -- à l'exception notable de l'accès aux données depuis le réseau -- l'accès qui prend le plus de temps sur un ordinateur.

    Du coup, le plus facile pour manipuler ces données est généralement de travailler en trois temps:
    1. tu charges les données en mémoire (par exemple, dans un std::vector<std::string>
    2. tu manipules les données "à ton aise" (et, qui sait, peut-être pourras tu le faire "par lot")
    3. tu réécris les données dans un nouveau fichier (auquel rien ne t'interdit de donner le même nom que le fichier original, ce qui en provoquera le remplacement)


    Bien sur, comme tu nous parle d'un fichier "d'un million de lignes", et que je n'ai aucune idée de leur taille, il est possible (même s'il en faudrait peut être dix ou cent fois plus) que tu sois confrontés à la limite des ressources de ton ordinateur.

    Ne t'en fais pas, tu le remarquera très rapidement, car, dans le meilleur des cas, ton application plantera, dans le pire des cas, ton ordinateur ralentira à un tel point que tu en viendra à décider de le redémarrer "sauvagement".

    Je sais, aucune des deux perspectives est attrayantes, mais ce sont pourtant des symptômes qui ne trompent pas

    Si cela t'arrive, il faudra juste envisager de ne lire que des "tronçons" de ton fichier (par exemple 1 000 ou 10 000 lignes) et de les traiter avant de les enregistrer dans un "fichier temporaire" et de recommencer avec le "tronçon" suivant jusqu'à ce que tu aies lu tout le fichier d'origine.

    Une fois que tu auras lu tout ton fichier, il ne te "restera plus qu'à" supprimer le fichier d'origine et le remplacer par le "fichier temporaire"
    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 averti
    Profil pro
    Inscrit en
    Décembre 2009
    Messages
    18
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2009
    Messages : 18
    Par défaut
    Je tiens à te remercier. Sans cette piste de vector, je ne m'en serais pas sorti. En fouillant sur le web, j'ai réussi à pondre un code qui me permet, notamment, de conserver le fichier de base intact et de bricoler les lignes sans perdre les modif. Pour l'instant, je crée un nouveau fichier. Le code, si cela peut servir :

    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
    int main()
    {
        string const fichierEntree("fichier.txt");
        string const fichierSortie ("sortie.txt");
        vector<string> data;
        ifstream fluxEntree(fichierEntree.c_str(), ios::in);
        ofstream fluxSortie(fichierSortie.c_str(), ios::app);
     
        if(fluxEntree)
        {
            string ligne;
            while(getline(fluxEntree, ligne))
            {
                  regex pattern { ", ," };
                  string target { ligne };
                  string replacement { "," };
                  ligne = regex_replace(target, pattern, replacement);
            }
                data.push_back(ligne);
            }
            fluxEntree.close();
        }
        else
        {
            cout << "Erreur : Impossible d'ouvrir le fichier !" << endl;
        }
     
        for(auto &ligne : data)
            fluxSortie << ligne << endl ;
        return 0;
    }
    Si j'ai bien tout compris, si je renomme le fichier de sortie comme le fichier d'entrée, le premier écrasera le second.
    Pour info, 1 million de lignes est le maxi, actuellement. Cependant cela va augmenter, et je ne pourrai plus ouvrir le fichier avec LibreOffice (Calc) d'où la recherche d'une autre solution.

  4. #4
    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 Phicome Voir le message
    Je tiens à te remercier. Sans cette piste de vector, je ne m'en serais pas sorti.
    De rien, c'est le but du forum, non:queston
    En fouillant sur le web, j'ai réussi à pondre un code qui me permet, notamment, de conserver le fichier de base intact et de bricoler les lignes sans perdre les modif.
    Ah, voilà un débutant comme je les aime! On lui donne une piste, et il sait faire une recherche pour trouver la suite
    Pour l'instant, je crée un nouveau fichier. Le code, si cela peut servir :

    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
    int main()
    {
        string const fichierEntree("fichier.txt");
        string const fichierSortie ("sortie.txt");
        vector<string> data;
        ifstream fluxEntree(fichierEntree.c_str(), ios::in);
        ofstream fluxSortie(fichierSortie.c_str(), ios::app);
     
        if(fluxEntree)
        {
            string ligne;
            while(getline(fluxEntree, ligne))
            {
                  regex pattern { ", ," };
                  string target { ligne };
                  string replacement { "," };
                  ligne = regex_replace(target, pattern, replacement);
            }
                data.push_back(ligne);
            }
            fluxEntree.close();
        }
        else
        {
            cout << "Erreur : Impossible d'ouvrir le fichier !" << endl;
        }
     
        for(auto &ligne : data)
            fluxSortie << ligne << endl ;
        return 0;
    }
    Code qui nécessite quelques remarques:

    1- L'abbsence de std:: devant tout ce qui vient de la bibliothèque standard me fait dire qu'il y a un using namespace std; qui traîne "quelque part".
    Or, la directive using namespace std; est une directive qui a été créée au tout début de la normalisation du C++, lorsque les espaces de noms sont apparus et que les normalisateurs ont décider de placer le contenu de la bibliothèque standard dans l'espace de noms std.

    Comme il y avait déjà une grosse quantité de code qui utilisait la bibliothèque standard, il fallait veiller à ce que ce code puisse continuer à travailler sans nécessiter "trop de modifications". La directive using namespace std est apparue comme étant "la moins mauvaise solution" permettant d'évtiter d'avoir trop de modification à apporter.

    Mais depuis, nous avons pu nous rendre compte que cette solution est surtout un pis-aller qui occasionne bien plus de problèmes qu'elle n'en résout. Et puis, le problème dont je te parle ne devrait en théorie toucher que du code qui a été écrit... il y a près de vingt ans

    2-
    • ios::in n'est pas nécessaire dés le moment où tu utilises std::ifstream: il sait que c'est un fichier de lecture
    • ios::app n'est nécessaire que si tu veux rajouter des informations en fin de fichier... Mais est-ce le cas
    • depuis l'arrivée de C++11 (qui remonte quand même à plus de 6 ans!!!) le constructeur de std::ifstream et de std::ofstream accepte qu'on lui transmette une std::string pour lui donner le nom du fichier. Il n'y a donc plus besoin d'utiliser c_str()


    3- Prends l'habitude de ne déclarer tes variable qu'au plus près de la première fois que tu les utilises.

    Vu que tu liras tout ton fichier "d'origine" avant même de commencer à écrire dans le fichier de "destination", les lignes
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
        string const fichierSortie ("sortie.txt");
    et
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ofstream fluxSortie(fichierSortie.c_str(), ios::app);
    pourraient être déplacées pour prendre place juste avant la ligne
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    for(auto &ligne : data)
    4- Prend l'habitude (plus importante encore) de séparer clairement les différentes responsabilités dans des fonctions séparées.

    Ici, ta fonction main() a quatre responsabilités:
    • servir de "point d'entrée" pour le système d'exploitation (totalement incontournable
    • lire des information depuis le "fichier d'origine"
    • effectuer des modifications sur base de expression régulière et
    • sauvegarder les modifications apportées dans le fichier de destination


    Cela fait trois responsabilités de trop pour la fonction main. Et donc, autant de responsabilités qu'elle devrait "déléguer" à d'autres fonctions.
    Au final, ta fonction main devrait ressembler à quelque chose comme:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    int main(){
        auto allLines = readFile("fichier.txt");
        makeChanges(allLines);
        writeFile("sortie.txt", allLines);
        return 0;
    }
    (à toi de créer les fonctions readFile, makeChanges et writeFile )

    Cela rendra ton code bien plus facile à comprendre
    Si j'ai bien tout compris, si je renomme le fichier de sortie comme le fichier d'entrée, le premier écrasera le second.
    Si les deux fichiers se trouvent dans le même dossier, oui
    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. Recherche fonction pour lire/ecrire fichier ISO
    Par T-B dans le forum Langage
    Réponses: 2
    Dernier message: 21/01/2008, 14h47
  2. Language (non sur serveur) lire/ecrire fichier texte / BDD
    Par jorisvh dans le forum Général Conception Web
    Réponses: 4
    Dernier message: 11/05/2006, 20h31
  3. [C#] Comment lire/ecrire dans fichier ini ?
    Par meli0207 dans le forum C#
    Réponses: 2
    Dernier message: 20/03/2006, 16h53
  4. Réponses: 5
    Dernier message: 24/02/2006, 00h27
  5. [CSV] Ecrire et Lire un fichier Excel depuis PHP
    Par cocaetjusdorange dans le forum Langage
    Réponses: 7
    Dernier message: 08/02/2006, 11h10

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