Bonjour,
comment détecte-t-on la fin d'un fichier texte?
une idée?
Bonjour,
comment détecte-t-on la fin d'un fichier texte?
une idée?
qu'en pensez-vous?
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 std::string readFileIntoString(const std::string path) { if (!entree.is_open()){ std::cerr << "Could not open the file - '" << path << "'" << std::endl; exit(1); } else{ return std::string((std::istreambuf_iterator<char>(entree)), std::istreambuf_iterator<char>()); } } int main(){ string fichier=readFileIntoString(path); taille=fichier.size(); /*puis, la variable qui indice fichier ne doit pas être supérieur à taille*/ }
Tout dépend des APIs utilisées. Il y en principalement 2:
La première utilise le concept "eof" qui retourne un entier (int_type) représentant un caractère (char_type) ou EOF. Par conséquent, sizeof(int_type) est supérieur à sizeof(char_type) et EOF n'est pas représentable dans un char_type. La manière usuelle de lire est la suivante:
Là, on suppose une API caractère par caractère. Quand on utilise un mode bloc, on passe un buffer et il y a une api style is_eof() pour savoir si on est à la fin ou non. EOF n'est pas la seule fin possible, il y a aussi les erreurs (corruption de fichier, etc), mais qui seront souvent gérées à part avec une valeur EOF représentant tous les cas d'erreurs.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 int_type result; while (EOF != (result = stream.getc())) { char_type ch = int_to_char(result); // qui n'est qu'un simple cast // ... }
Cela représente le comportement de FILE ou de std::streambuf. Pour std::istream, les fonctions retournent plutôt des booléens et il faut regarder rdstate()/is_eof().
Le second type d'API utilise le concept de peut lire, mais rien à lire. On demande de remplir un buffer et si 0 octet et lu, alors c'est la fin du fichier. C'est le fonctionnement d'une majorité — voir toutes — les APIs système (ex: read/write).
Avec ton exemple utilisant std::istreambuf_iterator, la détection se ferra avec entree.is_eof() (qui comme dit précédemment n'est pas la seule chose qui interrompe la lecture).
Mais si la question est comment lire efficacement un fichier ? On peut répondre en n'utilisant pas std::istreambuf_iterator.
Les itérateurs sur flux, c'est bien sympathique, mais c'est la méthode la plus lente. Il vaut mieux au moins faire des lectures par bloc et pré-allouer un buffer de la taille du fichier (avec std::filesystem::file_size() et string::reserve()/resize() en fonction de comment on s'y prend). L'idéal étant d'aligner la mémoire à la taille d'une page système, mais il faut un autre type que std::string (ou un autre allocateur).
On peut aussi ne pas lire le fichier complet et travailler avec un bloc de taille fixe.
Et si on veut vraiment être rapide (surtout pour les gros fichiers), on map un fichier en mémoire (mmap / CreateFileMapping).
Peux-tu me donner quelques exemples commentés?
Salut,
En fait, si tu utilise un fichier sous la forme d'un flux (comme ifstream ou ofstream), il faut savoir que les objets de ce type sont implicitement convertibles en booléen.
Pour faire simple, tant que tu obtiens true en les testant même d'une manière aussi barbare que [/c]if(monFluxDeFichier)[/c], c'est que ton flux est dans un état valide et prêt pour l'opération (de lecture ou d'écriture, selon le cas) suivante.
Alors, il y a -- effectivement -- des tonnes de raisons qui font que ton flux serait converti à false pour représenter un état invalide lors d'un de ces tests. Parmis lesquelles on retrouve, entre autre, le fait que la fin de fichier a été atteinte.
Cela signifie donc que tu risques d'avoir d'autres raisons que la fin de fichiers, mais, basiquement, un code proche de
fera sans doute parfaitement l'affaire dans la plupart des situations.
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 int main(){ std::ifstream ifs("monFichieer.txt"); //ouvre automatiquement le fichier indiqué if(!ifs) { // oups, le fichier n'a pas pu être ouvert throw std::runtime_error("unable to open the file"); // ca ne sert à rien d'essayer d'aller plus loin } /* C'est un fichier texte, je veux en récupérer les lignes une à une * je les récupérerai dans une chaine de caractères */ std::string temp; /* et je les placerai dans un tableau de chaines de caractères (pour utilisation ultérieure) */ std::vector<std::string> content. while(ifs) { // tant que le fichier est dans un état valide /* j'extrait du fichier tout ce qui précède le premier retour à la ligne */ std::getline(ifs, temp); /* et je rajoute le résultat à mon tableau */ content.push_back(temp); } /* Quand on arrive ici, le flux est dans un état invalide * sans doute parce que l'on a atteint la fin de fichier, * mais *** peut etre *** pour une autre raison */ /* ... */ }
Après, on peut appeler la fonction membre good() qui renverra true si le flux est dans un état valide, et qui a donc un comportement tout à fait similaire à la convertion implicite
Ou l'on peut également tester si le flux se trouve dans un état invalide bien particulier au travers des fonctions membres eof(), fail() et bad().
Il faut cependant noter que ces fonctions ( eof(), fail() et bad() ) ne renvoie true que lorsque l'erreur est déjà survenue, et donc que le flux est déjà dans un état invalide.
un code proche de
reste donc potentiellement dangereux parce que
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 while( ! ifs.eof()){ /* j'essaye d'extraire des données ici */ }
- on risque d'avoir déjà dépassé la fin de fichier avant que l'appel à eof ne renvoie true et
- on ne teste qu'un seul état sur trois qui soit susceptible d'indiquer que le fichier est devenu invalide
Il y a donc de gros risques qu'une dernière extraction soit tentée, alors que le flux est déjà dans un état invalide, avant que l'on ne se rende compte que c'est le cas... Ce qui forcera le flux à lancer une exception, qui risque de faire planter le programme...
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
Salut,
Comme eof() et fail() vont généralement de pair, il suffit, en fin d'opération, de valider le test if (file.eof() && ! file.bad()) pour avoir l'assurance que le fichier a été parcouru dans sa totalité.
Partager