#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 à propos de la fonction eof()
. Supposons que le contenu de mon ex.txt était:
abc
Il lit toujours un caractère supplémentaire et affiche -1
Lors de la lecture à l'aide de eof()
. Mais le inf >> c
A donné la sortie correcte qui était 'abc'? Quelqu'un peut-il m'aider à expliquer cela?
-1 est la manière de get
de dire que vous avez atteint la fin du fichier. Comparez-le en utilisant std::char_traits<char>::eof()
(ou std::istream::traits_type::eof()
) - évitez -1, c'est un nombre magique. (Bien que l'autre soit un peu prolixe - vous pouvez toujours appeler istream::eof
)
L’indicateur EOF n’est activé qu’une fois qu'une lecture a tenté de lire au-delà de la fin du fichier. Si j’ai un fichier de 3 octets et que je ne lis que 3 octets, EOF est false
, car je n'ai pas encore essayé de lire après la fin du fichier. Bien que cela semble déroutant pour les fichiers, qui connaissent généralement leur taille, EOF n'est pas connu jusqu'à ce qu'une lecture soit tentée sur certains périphériques, tels que les tubes 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
, dans un if
ou while
, sera évalué à true
si le fichier est "bon": pas d'erreur, pas de fin. Ainsi, lorsqu'une lecture échoue, inf
s'évase en false
et votre boucle est abandonnée 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, ceci:
while(inf >> x) // Attempt read into x, return false if it fails
{
// will only be entered if read succeeded.
}
C'est ce que nous voulons.
L’indicateur EOF est activé uniquement après une opération de lecture visant à lire après la fin du fichier. get()
renvoie la constante symbolique traits::eof()
(qui il se trouve que égal à -1) car il a atteint la fin du fichier et ne peut plus lire de données, et seulement à ce moment-là eof()
sera vraie. Si vous voulez vérifier cette condition, vous pouvez faire quelque chose comme ce qui suit:
int ch;
while ((ch = inf.get()) != EOF) {
std::cout << static_cast<char>(ch) << "\n";
}
iostream ne sait pas qu'il se trouve à la fin du fichier tant qu'il n'a pas essayé de lire le premier caractère après la fin du fichier.
Le exemple de code à l'adresse 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 langage consiste à déplacer la lecture dans la condition de boucle, comme suit: (Vous pouvez le faire avec all istream
opérations de lecture qui revenir *this
, incluant le >>
opérateur)
char c;
while(is.get(c))
cout << c;
eof () vérifie l'eofbit dans l'état du flux.
A chaque 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'avoir eofbit = 1.
La bonne façon est de vérifier si l'eof a été atteint (ou si l'opération de lecture a réussi) après l'opération de lecture. C’est ce que fait votre deuxième version: vous effectuez une opération de lecture, puis vous utilisez la référence d’objet de flux résultante (que >> renvoie) en tant que valeur booléenne, ce qui entraîne la vérification de fail ().