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 :

Utilisation de getline


Sujet :

C++

  1. #1
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2015
    Messages
    51
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2015
    Messages : 51
    Par défaut Utilisation de getline
    Bonsoir,
    Je suis un peu désespéré... je n'arrive toujours pas a comprendre le fonctionnement du getline. (Même après avoir checké 14 forum dans toutes les langues sur ce sujet ^^).

    En gros, j'ai un fichier.txt dans lequel j'ai une suite de mot ligne par ligne.
    Exemple:

    fleur
    maison
    vélo
    arbre
    etc...

    Et je cherche a "prendre" un mot a une ligne donnée.
    Pour faire un test j'ai utilisé ce code pour obtenir le premier mot de la ligne:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    ifstream liste("C:/Program Files/monprojet/liste.txt");
                    if(liste)
                    {
                        liste.seekg(ios::beg); //Je place le curseur au début du fichier
     
                        string mot;               
                        getline(liste, mot);   //Je prend la ligne d'où est placé le curseur pour le mettre dans "mot"
                        cout << mot << endl;
     
                        }
    Ne faites pas attention a la présentation du code je ne vous montre que la partie importante.

    Sauf que j'ai rien d'afficher.

    Après je pensais utiliser un while pour répéter cette action jusqu'à ma ligne pour finir avec le bon mot.

    Merci !

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

    Informations professionnelles :
    Activité : aucun

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

    Déjà, tu n'as pas besoin de te placer en début de fichier, car, comme tu viens de l'ouvrir, c'est là que tu te trouves d'office

    Ensuite, si tu veux lire toutes les lignes que contient ton fichier, il faut ... faire une boucle qui s'en chargera. En effet, std::getline va s'arrêter au premier caractère de délimitation qu'il rencontrera ( par défaut, elle utilise '\n' qui apparait en fin de ligne) ou à la fin du fichier.

    Du coup, si tu as un fichier qui prend la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    fleur
    maison
    vélo
    arbre
    étant donné qu'il y a un '\n' juste après fleur (et après maison et apres velo), la fonction s'arrêtera après avoir lu chaque mot. Or, tu voudrais sans doute pouvoir récupérer (et afficher, si l'on suit ton exemple) toutes les lignes de ton fichier.

    Par chance, std::getline renvoie une référence sur le flux qui a été utilisé pour l'extraction (ton fichier en l'occurrence) et les flux d'entrée sont implicitement convertible en booléen. Ce booléen présente la valeur true s'il est "dans un état qui permet l'extraction suivante" et la valeur false si... la dernière extraction effectuée a échoué. Or, il se fait que c'est "justement" ce qui se passe quand tu essaye d'extraire quelque chose après avoir rencontré la fin du flux : l'extraction qui arrive après ce point "stratégique" échoue.

    Tu peux donc créer une boucle signifiant "tant que getline arrive à extraire quelque chose", qui te permettra d'extraire toutes les lignes de ton fichier 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
    std::ifstream ifs("monFichier.txt");
    if(!ifs){ // si l'ouverture du fichier échoue
        throw std::runtime_error("impossible d'ouvrir le fichier"); // on lance une exception 
                                                                    // (cela ne sert à rien d'aller plus loin)
    }
    // si on arrive ici, c'est qu'on a pu ouvrir le fichier...
    // on prévoit une chaine de caractères pour l'extraction
    std::string ligne;
    while(std::getline(ifs, ligne)){ // tant que l'on arrive à extraire une ligne
        std::cout<<ligne<<"\n"; // on la manipule à notre guise
    }
    // arrivé ici, on a extrait toutes les lignes du 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

  3. #3
    Membre Expert

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2013
    Messages
    610
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Finance

    Informations forums :
    Inscription : Avril 2013
    Messages : 610
    Billets dans le blog
    21
    Par défaut
    En effet c'est la bonne méthode, et pourtant:
    while(std::getline(ifs, ligne)) { f(ligne); }
    cela veut dire que, si la dernière ligne n'est pas terminée par le séparateur de ligne, f(ligne) ne sera pas appelée pour cette dernière ligne, puisque getline renverra un flux avec le flag eof; je trouve ce comportement peu satisfaisant, 1) pcq il faut réfléchir un moment pour s'apercevoir du problème et 2) pcq la solution n'est pas élégante puisqu'elle consisterait à rappeler f à la sortie de la boucle après avoir testé si 'ligne' contient qqc...

  4. #4
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    Non, f sera bien appelé sur la dernière ligne.
    Quand getline arrive à lire des caractères avant d'atteindre le fichier, il ne met pas le flux en erreur, il s'arrête simplement et retourne la valeur lue. Ce n'est que quand il est déjà à la fin avant de comencer que le flux passe en erreur :

    Citation Envoyé par La norme, 21.4.8.9/7
    Effects: Behaves as an unformatted input function (as described in 27.7.2.3, paragraph 1). After constructing a sentry object, extracts characters and stores them into successive locations of an array whose first element is designated by s.319 Characters are extracted and stored until one of the following occurs:
    1. end-of-file occurs on the input sequence (in which case the function calls setstate(eofbit));
    2. traits::eq(c, delim) for the next available input character c (in which case the input characteris extracted but not stored);
    3. n is less than one or n - 1 characters are stored (in which case the function calls setstate(failbit)).
    These conditions are tested in the order shown.

    If the function extracts no characters, it calls setstate(failbit) (which may throw ios_base::failure (27.5.5.4))
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 633
    Par défaut
    Citation Envoyé par stendhal666 Voir le message
    En effet c'est la bonne méthode, et pourtant:

    cela veut dire que, si la dernière ligne n'est pas terminée par le séparateur de ligne, f(ligne) ne sera pas appelée pour cette dernière ligne, puisque getline renverra un flux avec le flag eof; je trouve ce comportement peu satisfaisant, 1) pcq il faut réfléchir un moment pour s'apercevoir du problème et 2) pcq la solution n'est pas élégante puisqu'elle consisterait à rappeler f à la sortie de la boucle après avoir testé si 'ligne' contient qqc...
    Pourquoi n'essaye tu pas

    Le flux (quel qu'il soit) n'est mis dans un état invalide que si l'extraction échoue, ce qui fait que tu entrera pour la dernière fois dans la boucle avec la dernière extraction réussie, qui correspond -- les choses sont quand même bien faites, hein à la dernière ligne que le flux contient.

    Il n'y aura donc aucun problème de "ligne oubliée", du moins, tant que tu suis cette logique
    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

  6. #6
    Membre Expert

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2013
    Messages
    610
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Finance

    Informations forums :
    Inscription : Avril 2013
    Messages : 610
    Billets dans le blog
    21
    Par défaut
    Mea culpa

    Merci pour ces précisions! A vrai dire je pensais que eofbit était un des flags d'erreur qui poussent ios::bool à retourner false...

    C'est en tout cas des subtilités à connaître lorsqu'on a besoin de faire sa propre fonction getline (par exemple si le séparateur de ligne peut apparaître dans la ligne tout en devant être ignoré, dans un fichier .csv par exemple: "123;123;\"123\n456\";123\n")

  7. #7
    Membre Expert
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Par défaut
    Citation Envoyé par stendhal666 Voir le message
    C'est en tout cas des subtilités à connaître lorsqu'on a besoin de faire sa propre fonction getline (par exemple si le séparateur de ligne peut apparaître dans la ligne tout en devant être ignoré, dans un fichier .csv par exemple: "123;123;\"123\n456\";123\n")
    getline est une mauvaise solution pour lire un csv. En partie à cause du problème que tu mentionnes, mais aussi pour d’autres raisons (problème si les données ne sont pas complètes, problème potentiel d’explosion mémoire avec un fichier conçu spécifiquement pour, etc...).

  8. #8
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2015
    Messages
    51
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2015
    Messages : 51
    Par défaut
    Bon finalement après avoir lu vos commentaires et essayé de les comprendre (avec mon niveau ^^ ).
    Il serai possible de pouvoir tout simplement demander au curseur de baisser d'une ligne ?
    Parce que pour l'instant le while ne permet que d'afficher tout le contenu d'un fichier :/
    Or j'ai besoin de n'en prélever qu'une ligne !

  9. #9
    Expert confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 432
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 432
    Par défaut
    Pour récupérer une ligne précise dans un fichier, il faut le lire depuis le début.
    Il vous suffit donc de changer les condition de sortie de la boucle while, ou faire une boucle for à la place de la boucle while.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 633
    Par défaut
    Ceci dit, la lecture d'un fichier est, très certainement, l'un des processus qui prend le plus de temps.
    Dans bien des cas, on préférera charger le fichier "une bonne fois pour toute" en mémoire en en mettant le contenu dans la collection "qui va bien" (par exemple un std::vector<std::string> dans lequel chaque élément correspond à une ligne de ton fichier), de manière à ce que le chargement du fichier ne se fasse qu'une seule fois au lancement de l'application et à pouvoir récupérer "n'importe quelle ligne" en utilisant simplement sa position dans le fichier comme indice du tableau
    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. bien utiliser getline et sscanf
    Par bobo696 dans le forum Débuter
    Réponses: 1
    Dernier message: 15/01/2010, 17h10
  2. Utilisation de getline
    Par dondano dans le forum C++
    Réponses: 4
    Dernier message: 17/12/2006, 19h34
  3. utilisation du meta type ANY
    Par Anonymous dans le forum CORBA
    Réponses: 1
    Dernier message: 15/04/2002, 12h36
  4. [BCB5] Utilisation des Ressources (.res)
    Par Vince78 dans le forum C++Builder
    Réponses: 2
    Dernier message: 04/04/2002, 16h01
  5. Réponses: 2
    Dernier message: 20/03/2002, 23h01

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