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é.
En fait, eof() va de pair avec fail(), dans le sens où, si eof() renvoie true, fail() le fera aussi.
Par contre, l'inverse n'est pas forcément vrai : fail() peut renvoyer true, parce que "quelque chose" s'est mal passé lors de l'extraction précédante, alors que eof() renvoie false, parce que ce n'était pas, techniquement parlant,la fin de 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
Salut,
Tu fais bien de paraphraser, ce n'était peut-être pas assez clair.
@deedolith m'a conseillé de charger tout le fichier, le traiter, puis enregistrer le résultat, si besoin.
est-ce un bon conseil?
Disons que cela permet de garder le fichier ouvert moins longtemps, avec tous les avantages que cela comporte (entre autre, le fait qu'il soit disponible pour d'autres systèmes qui tenteraient de le mettre à jour)
Ensuite, cela permet de clairement séparer les différentes étapes et donc, cela permet d'éviter d'essayer d'écrire dans un fichier qui est ouvert ... en lecture.
Enfin, cela a l'avantage de séparer clairement les différents problèmes, et donc, de simplifier la "logique" du traitement, ce qui est et sera toujours une bonne chose : ce n'est pas pour rien que le premier principe mis en avant par les principes SOLID est ... le SRP (Single responsibility Principle, ou principe de la responsabilité unique).
On peut donc dire que, dans l'absolu, c'est un excellent conseil et que tu as sans doute tout intérêt à le respecter.
Cependant, l'informatique est toujours une question de nuances, pour lesquelles il y a très peu de "vérités absolues" en dehors des lois ampiriques (qui, elles, resteront toujours vraies, remarque) : Il sera en effet toujours possible de trouver "LA circonstance particulière" dans laquelle la règle absolue ne sera pas applicable, et il faudra donc ... "faire avec".
Au final, la réponse se doit d'être : "dans l'absolu, oui, mais fais attentions aux circonstances particulières"![]()
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
Merci de m'avoir répondu
Partager