Compter le nombre de lignes d'un fichier [C] - C - Programmation
Marsh Posté le 27-02-2006 à 22:39:34
te fais pas chier avec les i/o posix (open, read,...), utilise fopen et le type FILE, apres il suffit de boucler sur fgetc et de compter le nombre de caractere ayant la valeur '\n' (le nombre de ligne == le nombre de caractere de fin de ligne)
Marsh Posté le 27-02-2006 à 23:50:17
non, en fait '\n' est un caractere de fin de ligne ou de nouvelle ligne (n -> newline), le compte est toujours bon et si tu fais allusion à un fichier qui se termine par un '\n' ca veut juste dire qu'il se termine par une ligne vide
Marsh Posté le 28-02-2006 à 00:41:11
skelter a écrit : te fais pas chier avec les i/o posix (open, read,...), utilise fopen et le type FILE, apres il suffit de boucler sur fgetc et de compter le nombre de caractere ayant la valeur '\n' (le nombre de ligne == le nombre de caractere de fin de ligne) |
Cependant, cette solution est clairement très couteuse. En gros, tu provoques plein d'I/O caractère par caractère, ce qui est très porc. Le mieux est donc de prendre bloc par bloc de 1024 octets (par exemple) et de parcourir ce buffer (tu lis ensuite la mémoire octet par octet). Ce n'est pas une solution très élégante non plus, mais c'est une des premières idées qui me vient.
Marsh Posté le 28-02-2006 à 00:43:13
mes fesses, memory mapping sur le fichier, parcours de bourrin pour trouver \n et vlan.
cinq lignes de code a tout peter, et peinard niveau perfos
Marsh Posté le 28-02-2006 à 00:43:40
le memory mapping pour les fichiers textes, la solution pour nous, les feneasses
Marsh Posté le 28-02-2006 à 03:43:24
skelter a écrit : non, en fait '\n' est un caractere de fin de ligne ou de nouvelle ligne (n -> newline), le compte est toujours bon et si tu fais allusion à un fichier qui se termine par un '\n' ca veut juste dire qu'il se termine par une ligne vide |
Non, je pensais au cas (courant) où la dernière ligne ne se termine pas pas "\n".
s0d4 a écrit : Cependant, cette solution est clairement très couteuse. En gros, tu provoques plein d'I/O caractère par caractère, ce qui est très porc. Le mieux est donc de prendre bloc par bloc de 1024 octets (par exemple) et de parcourir ce buffer (tu lis ensuite la mémoire octet par octet). Ce n'est pas une solution très élégante non plus, mais c'est une des premières idées qui me vient. |
C'est justement en gros ce que fait la libc avec fread. D'où le conseil skelter d'utiliser fopen/fread plutôt que open/read. Réinventer la roue et se faire des buffers à la main, c'est stupide.
Marsh Posté le 28-02-2006 à 09:12:48
ReplyMarsh Posté le 28-02-2006 à 09:55:42
s0d4 a écrit : Cependant, cette solution est clairement très couteuse. En gros, tu provoques plein d'I/O caractère par caractère, ce qui est très porc. |
Pas sûr. Sur les systèmes modernes, les fonctions standards sont bufferisées et optimisées, et les I/Os réels sont automatiquement limités au strict minimum. Le premier fgetc() va par exemple appeler read(fd, block, 512), le second va fouiller dans le bloc chargé. etc.
Faire des mesures avant de se lancer dans des raisonnements douteux...
Marsh Posté le 28-02-2006 à 09:57:22
matafan a écrit : Non, je pensais au cas (courant) où la dernière ligne ne se termine pas pas "\n". |
Dans ce cas, ce n'est pas une ligne -> poubelle.
La prochaine fois, le gars qui écrit le fichier texte fera attention...
Marsh Posté le 28-02-2006 à 09:59:59
franceso a écrit : pourquoi pas une boucle sur un fgets() ? |
Parce qu'on ne connait pas la longueur des lignes à l'avance. Il va falloir appeler strchr() à chaques fois pour savoir si la ligne est complète... Pas efficace. La seule méthode standard efficace est la lecture par bytes et le comptage direct des '\n'. Ensuite la méthode avec mmap() est encore meilleure, mais non standard.
Marsh Posté le 28-02-2006 à 10:12:43
ReplyMarsh Posté le 28-02-2006 à 10:20:03
skelter a écrit : jamais utilisé mais les fonctions setbuf et setvbuf sont standards (c89) |
Et ? Les reglages par défaut sont, en principe, optimsés pour le système. Les modifier risque de réduire les performances...
Marsh Posté le 28-02-2006 à 10:25:57
je sais pas, on peut avoir de meilleurs performances avec un buffer plus gros sans rien changer au code ?
Marsh Posté le 28-02-2006 à 10:27:39
ca te dis mon gros buffer dans tes petites performances ?
Marsh Posté le 28-02-2006 à 10:33:38
oue de toute facon suffit d'essayer mais moi je m'en fout j'ai jamais utilisé ni meme vos pas portable de file mapping
Marsh Posté le 28-02-2006 à 10:34:57
le file mapping, c'est du bonheur en barre à tartiner. ca te fait genre un gros char * en mémoire (sauf que le \0 a la fin est pas garanti, donc strn* en force) et vlan. En plus sous nux c'est tout con a faire (sous win c'est un peu plus pénible).
Marsh Posté le 28-02-2006 à 10:54:19
Merci pour vos réponses!
En fait je DOIS utiliser les I/O posix bas niveau pour ce programme, c'est un tp et la je sèche vraiment!
Sinon ya pas moyen d'utiliser la commande système wc -l directement dedans?
Marsh Posté le 28-02-2006 à 10:58:39
delantera a écrit : En fait je DOIS utiliser les I/O posix bas niveau pour ce programme, c'est un tp et la je sèche vraiment! |
C'est nul. C'est quoi cette école ?
Citation : Sinon ya pas moyen d'utiliser la commande système wc -l directement dedans? |
Ben si, avec system()...
Marsh Posté le 28-02-2006 à 11:30:31
Ben c pour nous apprendre a utiliser le bas niveau, la suite du TP est en haut niveau et pi c un IUT info
Je vais essayer avec system() alors, merci
Marsh Posté le 28-02-2006 à 11:32:09
Emmanuel Delahaye a écrit : C'est nul. C'est quoi cette école ? |
bah entre ca et les profs de C++ qui refusent que leur eleves utilisent la STL et les force a utiliser du char * ...
Marsh Posté le 28-02-2006 à 16:16:53
delantera a écrit : Sinon ya pas moyen d'utiliser la commande système wc -l directement dedans? |
"wc" n'est pas une commande système, c'est une commande point. Un gars a un jour écrit un pgm en C qui prend 30 lignes et l'a nommé "wc.c" puis l'a compilé. Mais pour répondre à ta question, si vraiment c'est un devoir alors le prof fera un peu plus que d'exécuter ton code, il jettera aussi un oeuil dedans...
delantera a écrit : En fait je DOIS utiliser les I/O posix bas niveau pour ce programme, c'est un tp et la je sèche vraiment! |
Méthode bourrin
|
Marsh Posté le 28-02-2006 à 18:51:42
C'est pas un devoir mais un TP personnel, je suis pas noté dessus!
Merci pour ta réponse, je vais essayer ça!
Marsh Posté le 28-02-2006 à 19:44:55
delantera a écrit : C'est pas un devoir mais un TP personnel, je suis pas noté dessus! |
Alors profites en pour apprendre à utiliser les fonctions du C et pas les fonctions de quelque obscur système...
fgetc()
Marsh Posté le 28-02-2006 à 20:23:58
Ca marche, merci bien
Bon si j'ai 3 lignes avec pas de retour à la ligne ça m'en marque que 2 mais ça ira merci
Marsh Posté le 28-02-2006 à 23:02:12
delantera a écrit : C'est pas un devoir mais un TP personnel, je suis pas noté dessus! |
Ben alors essaye de partir de cette base en l'améliorant. Par exemple, au lieu de lire un caractère à la fois que tu stockes dans un "char", lis-en "n" à la fois que tu stockeras dans un tableau de "char [n]" ("n" pouvant être de la valeur que tu veux mais sans dépasser 32767). Et ensuites, tu balayes ce tableau en utilisant un pointeur (pour t'entrainer à les manipuler) en comptabilisant chaque '\n'. Et sans oublier que ce n'est pas parce que tu lis "n" caractères que t'en auras forcément "n" qui te seront donnés (surtout à la fin du fichier) mais en sachant que la valeur que renvoie "read" est justement le nombre de caractères réellement lus...
delantera a écrit : Ca marche, merci bien |
Evidemment...
delantera a écrit : Bon si j'ai 3 lignes avec pas de retour à la ligne ça m'en marque que 2 mais ça ira merci |
Ben si t'as pas de retour à la ligne c'est que ta ligne n'est pas complète donc ce n'est pas une ligne...
Marsh Posté le 03-03-2006 à 02:10:33
Emmanuel Delahaye a écrit : |
Bravo, tu viens d'apprendre ce qu'est le buffer cache dans un noyau. Cependant, ce n'est pas une raison pour coder comme un porc. Si demain tu arrives sur un système qui n'a pas un tel système de cache (embarqué, etc ...), tu seras bien dans la merde. Donc, bien coder, prendre des bonnes habitudes, cela se fait tout le temps.
Marsh Posté le 03-03-2006 à 07:32:38
Rien à voir avec un quelconque "buffer cache dans un noyau". Et les fopen, fgetc et autres setvbuf font partie du C ANSI. Si tu veux prendre les gens de haut, fais le plutôt sur un sujet que tu maitrise.
Marsh Posté le 04-03-2006 à 03:38:01
Ah ? tu crois que c'est ta fonction fgets qui va aller bufferiser ce qu'il y a avant/après ce qu'il y a ce que tu souhaites lire ? Non. fgets fait lui un appel système (read), qui lui ensuite va aller voir dans le noyal ce qu'il faut prendre, et le noyal va lire plus de données qu'il n'en faut pour ne pas avoir à lire au prochain read. On appelle ça un cache, et là, en l'occurence, le buffer cache ... C'est ce que notre ami nous expliquait. Et mon post disait que oui, ça permet d'avoir une bonne vitesse d'execution, mais ça ne permettait pas de s'affranchir de bien coder.
Bon, après, tu peux faire ce que tu veux, hein, penser que finalement, tes fonctions posix de merde font tout et même le café, grand bien te fasse, mais bon, hein, quand même.
Marsh Posté le 04-03-2006 à 04:15:16
Perdu. Oui justement, la bufferisation est faite par la libc. Quand tu fais un appel a fgetc, la libc va typiquement appeler read (le sytem call) pour lire un bloc complet de données (généralement 4kB, mais ça peut évidemment varier d'une platefome à l'autre). Les appels ultérieurs à fgetc piochent ensuite dans le buffer de la libc, sans appel à read. L'avantage c'est que ca limite le nombre de system call, qui sont en toujours en eux-même très couteux (sauvegarde du contexte, copyout...).
Puisque tu m'a l'air difficile à convaincre, je te suggère d'écrire un petit programe et de vérifier avec strace ce qui se passe quand tu l'exécutes.
Marsh Posté le 04-03-2006 à 08:31:35
matafan a écrit : Perdu. Oui justement, la bufferisation est faite par la libc. Quand tu fais un appel a fgetc, la libc va typiquement appeler read (le sytem call) pour lire un bloc complet de données (généralement 4kB, mais ça peut évidemment varier d'une platefome à l'autre). Les appels ultérieurs à fgetc piochent ensuite dans le buffer de la libc, sans appel à read. L'avantage c'est que ca limite le nombre de system call, qui sont en toujours en eux-même très couteux (sauvegarde du contexte, copyout...). |
Absolument. Et la taille de ces fameux buffers de la libc sont gérés par les fonctions standard setbuf() et setvbuf().
http://maconlinux.net/linux-man-pages/fr/setbuf.3.html
http://maconlinux.net/linux-man-pa [...] buf.3.html
Marsh Posté le 06-03-2006 à 20:43:18
matafan a écrit : Perdu. Oui justement, la bufferisation est faite par la libc. Quand tu fais un appel a fgetc, la libc va typiquement appeler read (le sytem call) pour lire un bloc complet de données (généralement 4kB, mais ça peut évidemment varier d'une platefome à l'autre). Les appels ultérieurs à fgetc piochent ensuite dans le buffer de la libc, sans appel à read. L'avantage c'est que ca limite le nombre de system call, qui sont en toujours en eux-même très couteux (sauvegarde du contexte, copyout...). |
Shame on me !
Bon, cela dit, je maintiens toujours que c'est pas parce que la libc bufferise comme une grande qu'il faut coder comme un porc :-)
Marsh Posté le 06-03-2006 à 20:51:54
s0d4 a écrit : Ah ? tu crois que c'est ta fonction fgets qui va aller bufferiser ce qu'il y a avant/après ce qu'il y a ce que tu souhaites lire ? Non. fgets fait lui un appel système (read), qui lui ensuite va aller voir dans le noyal ce qu'il faut prendre, et le noyal va lire plus de données qu'il n'en faut pour ne pas avoir à lire au prochain read. On appelle ça un cache, et là, en l'occurence, le buffer cache ... C'est ce que notre ami nous expliquait. Et mon post disait que oui, ça permet d'avoir une bonne vitesse d'execution, mais ça ne permettait pas de s'affranchir de bien coder. |
j'adore ce genre de post plein de diplomacie, de pédagogie et surtout, de modestie .... ...... et completement faux
merci donc pour ce grand moment
Marsh Posté le 06-03-2006 à 20:56:38
s0d4 a écrit : Shame on me ! |
Et utiliser les fonctions standard, c'est programmer comme un porc ? Alors groiiink.
http://www.old-hippie.com/sound_fi [...] /1pig1.wav
Marsh Posté le 06-03-2006 à 21:00:18
ReplyMarsh Posté le 07-03-2006 à 08:40:53
chrisbk a écrit : un vrai codeur recode tout lui meme |
fait comme tout le monde, utilise celle de BSD
( et coder propre malgrès les fct déja existantes c'est malin, tu te retrouve avec deux buffers en enfilade, un qui sert a rien, qui bouffe de la mémoire, du code pour le gérer qui sert aussi à rien, et qui est susceptible comme tout bon code de contenir des erreurs. de la propreté qui réduis les perfs tout en rendant le code moins compréhensible, bravo )
Marsh Posté le 27-02-2006 à 22:04:35
Bonjour,
J'ai cherché partout sur le net mais je trouve pas alors je me permets de poster içi...
Je desirerais faire un programme C qui compterai le nombre de lignes d'un fichier mis en paramètre à l'execution, à la manière de la commande Unix wc -l.
Je vous montre ce que j'ai déja fait:
Je sais vraiment pas comment faire, j'ai pensé à faire un compteur mais je sais pas comment parcourir le fichier!
Merci de votre aide...
PS: je sais que j'ai pas besoin de toutes ces libs, mais j'ai fait un copier/coller d'un autre prog.
Message édité par delantera le 27-02-2006 à 22:17:09