Comment fonctionne EOF() d'ifstream?
#include <iostream>
#include <fstream>
int main() {
std::fstream inf( "ex.txt", std::ios::in );
while( !inf.eof() ) {
std::cout << inf.get() << "n";
}
inf.close();
inf.clear();
inf.open( "ex.txt", std::ios::in );
char c;
while( inf >> c ) {
std::cout << c << "n";
}
return 0;
}
Je suis vraiment confus au sujet de la fonction eof()
. Supposons que mon ex.le contenu de txt était:
abc
Il lit toujours un caractère supplémentaire et affiche -1
lors de la lecture en utilisant eof()
. Mais le inf >> c
a donné la sortie correcte qui était 'abc'? Quelqu'un peut-il m'aider à expliquer cela?
4 réponses
-1 est la façon de get
de dire que vous avez atteint la fin du fichier. Comparez-le en utilisant le std::char_traits<char>::eof()
(ou std::istream::traits_type::eof()
) - évitez -1, c'est un nombre magique. (Bien que l'autre est un peu verbeux - vous pouvez toujours appeler istream::eof
)
L'indicateur EOF n'est défini qu'une fois qu'une lecture a essayé de lire après la fin du fichier . Si j'ai un fichier de 3 octets, et que je ne lis que 3 octets, EOF est false
, parce que je n'ai pas encore essayé de lire après la fin du fichier. Bien que cela semble déroutant pour les fichiers, qui généralement connaître leur taille, EOF n'est pas connu jusqu'à ce qu'une lecture soit tentée sur certains périphériques, tels que les tuyaux et les sockets réseau.
Le deuxième exemple fonctionne comme inf >> foo
retournera toujours inf
, avec l'effet secondaire de tenter de lire quelque chose et de le stocker dans foo
. inf
, un if
ou while
, permettra d'évaluer à true
si le fichier est "bon": pas d'erreurs, pas d'expressions du FOLKLORE. Ainsi, lorsqu'une lecture échoue, inf
evaule à false
, et votre boucle s'arrête correctement. Cependant, prenez cette erreur commune:
while(!inf.eof()) // EOF is false here
{
inf >> x; // read fails, EOF becomes true, x is not set
// use x // we use x, despite our read failing.
}
Cependant, ce:
while(inf >> x) // Attempt read into x, return false if it fails
{
// will only be entered if read succeeded.
}
, Qui est ce que nous voulons.
Iostream ne sais pas, c'est à la fin du fichier jusqu'à ce qu'il essaie de lire ce premier caractère après la fin du fichier.
Le Exemple de code à cplusplus.com dit de le faire comme ceci: (mais vous ne devriez pas le faire de cette façon)
while (is.good()) // loop while extraction from file is possible
{
c = is.get(); // get character from file
if (is.good())
cout << c;
}
Un meilleur idiome est de déplacer la lecture dans la condition de boucle, comme ceci:
(Vous pouvez le faire avec all istream
Lire les opérations qui renvoient *this
, y compris l'opérateur >>
)
char c;
while(is.get(c))
cout << c;
L'indicateur EOF n'est défini qu'après une opération de lecture qui tente de lire après la fin du fichier. get()
retourne la constante symbolique traits::eof()
(qui arrive juste à égaler -1) parce qu'elle a atteint la fin du fichier et n'a pas pu lire plus de données, et seulement à ce stade sera eof()
vrai. Si vous voulez vérifier cette condition, vous pouvez faire quelque chose comme ceci:
int ch;
while ((ch = inf.get()) != EOF) {
std::cout << static_cast<char>(ch) << "\n";
}
EOF () vérifie l'eofbit dans l'état du flux.
À chaque opération de lecture, si la position est à la fin du flux et que plus de données doivent être lues, eofbit est défini sur true. Par conséquent, vous allez obtenir un caractère supplémentaire avant d'obtenir eofbit=1.
La bonne façon est de vérifier si les expressions du folklore a été atteint (ou, si l'opération de lecture a réussi) après la lecture. C'est ce que fait votre deuxième version - vous faites une opération de lecture, puis utilisez le résultat référence d'objet de flux (qui >> renvoie) en tant que valeur booléenne, ce qui entraîne une vérification de fail().