Lecture à partir d'un fichier texte jusqu'à ce qu'EOF répète la dernière ligne [duplicata]

StackOverflow https://stackoverflow.com/questions/21647

  •  09-06-2019
  •  | 
  •  

Question

Ce qui suit C++ le code utilise un ifstream objet pour lire des entiers à partir d'un fichier texte (qui a un nombre par ligne) jusqu'à ce qu'il atteigne EOF.Pourquoi lit-il deux fois le nombre entier de la dernière ligne ?Comment régler ceci?

Code:

#include <iostream>
#include <fstream>
using namespace std;

int main()
{
    ifstream iFile("input.txt");    // input.txt has integers, one per line

    while (!iFile.eof())
    {
        int x;
        iFile >> x;
        cerr << x << endl;
    }

    return 0;
}

entrée.txt:

10  
20  
30

Sortir:

10  
20  
30  
30

Note:J'ai ignoré tout le code de vérification des erreurs pour garder l'extrait de code petit.Le comportement ci-dessus est observé sous Windows (Visual C++), cygwin (gcc) et Linux (gcc).

Était-ce utile?

La solution

Il suffit de suivre de près la chaîne des événements.

  • Prenez-en 10
  • Prenez-en 20
  • Prenez 30
  • Saisissez EOF

Regardez l'avant-dernière itération.Vous en avez attrapé 30, puis avez continué à vérifier l'EOF.Vous n'avez pas atteint EOF car la marque EOF n'a pas encore été lue ("binairement parlant", son emplacement conceptuel est juste après la ligne 30).Vous passez donc à l’itération suivante.x est toujours égal à 30 par rapport à l'itération précédente.Maintenant, vous lisez le flux et vous obtenez EOF.x reste 30 et le ios::eofbit est augmenté.Vous sortez vers stderr x (qui vaut 30, tout comme dans l'itération précédente).Ensuite, vous vérifiez EOF dans la condition de boucle, et cette fois vous êtes hors de la boucle.

Essaye ça:

while (true) {
    int x;
    iFile >> x;
    if( iFile.eof() ) break;
    cerr << x << endl;
}

Au fait, il y a un autre bug dans votre code.Avez-vous déjà essayé de l'exécuter sur un fichier vide ?Le comportement que vous obtenez est exactement pour la même raison.

Autres conseils

J'aime cet exemple, qui pour l'instant laisse de côté la vérification que vous pourriez ajouter à l'intérieur du bloc while :

ifstream iFile("input.txt");        // input.txt has integers, one per line
int x;

while (iFile >> x) 
{
    cerr << x << endl;
}

Je ne sais pas à quel point c'est sûr...

Il existe une approche alternative à cela :

#include <iterator>
#include <algorithm>

// ...

    copy(istream_iterator<int>(iFile), istream_iterator<int>(),
         ostream_iterator<int>(cerr, "\n"));

Le modèle EOF a besoin d'une lecture principale pour « amorcer » le processus de vérification EOF.Considérez que le fichier vide n'aura pas initialement son EOF défini avant la première lecture.La lecture principale interceptera l'EOF dans ce cas et ignorera complètement la boucle.

Ce que vous devez retenir ici, c'est que vous n'obtenez l'EOF qu'à la première tentative de lecture des données disponibles du fichier.La lecture de la quantité exacte de données ne signalera pas l'EOF.

Je dois souligner que si le fichier était vide, votre code donné aurait été imprimé puisque l'EOF aurait empêché qu'une valeur soit définie sur x lors de l'entrée dans la boucle.

  • 0

Ajoutez donc une lecture principale et déplacez la lecture de la boucle jusqu'à la fin :

int x;

iFile >> x; // prime read here
while (!iFile.eof()) {
    cerr << x << endl;
    iFile >> x;
}

Sans trop de modifications du code original, cela pourrait devenir :

while (!iFile.eof())
{  
    int x;
    iFile >> x;
    if (!iFile.eof()) break;
    cerr << x << endl;
}

mais je préfère les deux autres solutions ci-dessus en général.

int x;
ifile >> x

while (!iFile.eof())
{  
    cerr << x << endl;        
    iFile >> x;      
}

A la fin de la dernière ligne, vous avez un caractère de nouvelle ligne, qui n'est pas lu par l'opérateur >> et ce n'est pas une fin de fichier.S'il vous plaît, faites une expérience et supprimez la nouvelle ligne (le dernier caractère du fichier) - vous n'obtiendrez pas de duplication.Pour avoir un code flexible et éviter les effets indésirables, appliquez simplement n'importe quelle solution proposée par d'autres utilisateurs.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top