IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

Problème de traitement aléatoire EOF


Sujet :

C

  1. #1
    Futur Membre du Club
    Inscrit en
    Novembre 2007
    Messages
    4
    Détails du profil
    Informations forums :
    Inscription : Novembre 2007
    Messages : 4
    Par défaut Problème de traitement aléatoire EOF
    Bonjour à tous
    - Pour parcourir mon fichier j'utilise
    Mes déclarations

    #define MAX_REC_LEN 2044
    char bufline[MAX_REC_LEN+2];
    FILE* curr_file;

    while ((code = read_line()) != EOF)
    {
    ...

    -La fonction read_line est la suivante:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    int read_line()
    {
    	memset(bufline,0,MAX_REC_LEN+2);
    	if (fgets(bufline, MAX_REC_LEN+2, curr_file)==NULL)
    	{
    		return EOF;
    	}
    	if (bufline[0]==0) return EOF;
    	return 1;
    }
    curr_file: Mon fichier
    bufline : est censé contenir la ligne du fichier.

    Mon problème c'est que ma fonction read_line me retourne parfois un EOF (le premier) directement, mais ce problème est aléatoire, je remets le même fichier dans le répertoire de traitement et il est traité sans problème.

    Est ce que c'est possible que ça soit un problème de mémoire ? ou c'est autre chose ?

    Merci pour votre aide

  2. #2
    Invité
    Invité(e)
    Par défaut
    Bonjour,
    C'est quoi EOF?
    Ca veut dire "End Of File", mais je ne pense pas que ce soit une constante définie.
    Habituellement, on écrit cela
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    FILE *in=fopen("fictier","rt"); // ou autre-chose
    while (!feof(in))
    {
    ...
    //lecture
    ...
    } 
    fclose(in);
    Si vous replacez EOF par 0 (par exemple) vous y verrez déjà plus clair.

  3. #3
    Membre Expert
    Profil pro
    Inscrit en
    Août 2006
    Messages
    1 104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 1 104
    Par défaut
    Comment ta fonction connait le pointeur sur le fichier si tu ne lui passes pas en argument ? Même chose pour bufline... Ce sont des globales ?

    Dans l'ordre :
    Il faut ouvrir le fichier.
    Vérifier s'il est bien ouvert.
    Si tout est bon : ensuite, tu peux lire chaque ligne via ta fonction en lui passant le pointeur sur le fichier et l'adresse où écrire la ligne (bufline), en argument.

    Je ne comprends pas l'utilité du memset. S'il s'agit d'un fichier texte, la ligne est censée se terminer par un '\n' (qui pourra être supprimé par la suite en le remplaçant par un '\0'). Et s'il n'y en a pas, c'est que le buffer est trop petit. Remplir toute la ligne avec le caractère '\0' avant chaque lecture consomme des ressources inutilement.

  4. #4
    Futur Membre du Club
    Inscrit en
    Novembre 2007
    Messages
    4
    Détails du profil
    Informations forums :
    Inscription : Novembre 2007
    Messages : 4
    Par défaut
    Oui c'est bien END OF FILE, elle est définit dans un autre fichier, mais j'ai oublié de mentionner ça.

    Ce que je n'ai pas compris, c'est que c'est un problème aléatoire, je n'ai pas toujours ce problème.

  5. #5
    Invité
    Invité(e)
    Par défaut
    Avez regardé le bout de code que j'ai écrit et ce qu'a écrit jeroman.?

  6. #6
    Futur Membre du Club
    Inscrit en
    Novembre 2007
    Messages
    4
    Détails du profil
    Informations forums :
    Inscription : Novembre 2007
    Messages : 4
    Par défaut
    Citation Envoyé par jeroman Voir le message
    Comment ta fonction connait le pointeur sur le fichier si tu ne lui passes pas en argument ? Même chose pour bufline... Ce sont des globales ?

    Dans l'ordre :
    Il faut ouvrir le fichier.
    Vérifier s'il est bien ouvert.
    Si tout est bon : ensuite, tu peux lire chaque ligne via ta fonction en lui passant le pointeur sur le fichier et l'adresse où écrire la ligne (bufline), en argument.

    Je ne comprends pas l'utilité du memset. S'il s'agit d'un fichier texte, la ligne est censée se terminer par un '\n' (qui pourra être supprimé par la suite en le remplaçant par un '\0'). Et s'il n'y en a pas, c'est que le buffer est trop petit. Remplir toute la ligne avec le caractère '\0' avant chaque lecture consomme des ressources inutilement.
    salut,
    C'est ce que je fais.
    j'ouvre le fichier
    if ((curr_file = fopen(filename,"r")) == NULL) return 0

    sinon la ligne se termine par un 0D 0A (Hex)
    un exemple de mon fichier en pièce jointe.

    Désolé si je l'ai répété, mais je ne comprends pas pourquoi la problème est aléatoire.

    Pierre Dolez
    Oui je viens de voir, merci, je vais essayer de modifier mon code. mais j'ai toujours utilisé cette fonction et je n'avais jamais eu un tel problème avant.

    Merci
    Fichiers attachés Fichiers attachés

  7. #7
    Invité
    Invité(e)
    Par défaut
    Votre fichier contient une seule ligne très longue.
    Il faut le lire autrement.

  8. #8
    Expert confirmé
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Par défaut
    Citation Envoyé par Pierre Dolez Voir le message
    Bonjour,
    C'est quoi EOF?
    Ca veut dire "End Of File", mais je ne pense pas que ce soit une constante définie.
    ....
    Si vous replacez EOF par 0 (par exemple) vous y verrez déjà plus clair.
    EOF est une constante définie comme étant un int de valeur négative. Elle est définie dans <stdio.h>

  9. #9
    Invité
    Invité(e)
    Par défaut
    Exact, pardon.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    #define EOF (-1)                /* End of file indicator */

  10. #10
    Membre Expert
    Profil pro
    Inscrit en
    Août 2006
    Messages
    1 104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 1 104
    Par défaut
    Je soupçonne l'utilisation de globales (car ta fonction de lecture n'a aucun argument), c'est pas propre et source de bugs (on peut modifier la valeur n'importe où dans le code).

    Ce code (une ébauche), qui sert d'exemple, fonctionne chez moi. A adapter.
    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
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    #include <stdio.h>
     
    #define MAX_REC_LEN 2044
     
    int read_line(char * bufline , int taille , FILE * curr_file)
    {
        if ( fgets(bufline , taille , curr_file) == NULL )
        {
            return EOF;
        }
     
        /* A FAIRE : rechercher '\n' ou "\r\n" et remplacer par '\0' */
     
        if (bufline[0] == 0)
            return EOF;
     
        return 1;
    }
     
    int main(void)
    {
        int code;
        int numero_ligne = 0;
        char bufline[MAX_REC_LEN+2];
        FILE* curr_file;
     
        if ((curr_file = fopen("Fichier.txt","rb")) == NULL)
            return 0;
     
        while ( (code = read_line(bufline , MAX_REC_LEN+2 , curr_file)) != EOF )
        {
            numero_ligne++;
            printf( "ligne %d : %s" , numero_ligne , bufline );
        }
     
        return 0;
    }
    J'ai viré le memset, qui ne sert à rien. Il y a des choses à rajouter (voir commentaire).

    Je ne comprend pas pourquoi créer un tableau de dimension REC_LEN+2. Pourquoi +2 ? Et pourquoi précisément 2044 ? J'ai laissé tel quel, mais je trouve ça bizarre.

  11. #11
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Citation Envoyé par Sixclopes Voir le message
    Est ce que c'est possible que ça soit un problème de mémoire ?
    Le problème ne vient pas de ce qui est montré, même si le code n'est pas d'un style particulièrement à conseiller.

    Citation Envoyé par Pierre Dolez Voir le message
    Habituellement, on écrit cela
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    FILE *in=fopen("fictier","rt"); // ou autre-chose
    while (!feof(in))
    {
    ...
    //lecture
    ...
    } 
    fclose(in);
    J'espère bien que non. Habituellement l'utilisation de feof pour contrôler une boucle dénote plutôt une mauvaise compréhension du comportement des IO en C. Si le code de l'OP est stylistiquement pas à conseiller, une telle utilisation de feof est généralement erronée.

    La boucle de lecture par ligne canonique en C est
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    while (!fgets()) {
       /* vérification de tampon trop court */
       /* utilisation */
    }
    if (ferror(...)) {
       /* erreur d'IO */
    } else {
       /* fin de fichier */
    }

  12. #12
    Invité
    Invité(e)
    Par défaut
    Bonjour,
    Habituellement l'utilisation de feof pour contrôler une boucle dénote plutôt une mauvaise compréhension du comportement des IO en C. Si le code de l'OP est stylistiquement pas à conseiller, une telle utilisation de feof est généralement erronée.
    Il serait intéressant de préciser une utilisation de feof() "à conseiller".
    Dans votre exemple, vous faites une lecture du fichier avec fgets(). En réalité, et dans le cas général, la lecture peut être faite avec plusieurs fonctions, et un bonne gestion prévoira la présence d'une donnée marquent la fin du fichier, de façon à sortir de la bouche while.
    En quelque-sorte, l'instruction !feof(in) est là par sécurité et dans la pratique, un programme doit prévoir cette instruction et les instructions de lecture seront à l'intérieur de la boucle.
    D'ailleurs, à titre personnel, je n'utilise fgets() que dans les cas où je suis sûr de l'organisation en lignes, par exemple un fichier CSV. C'est à dire que j'utilise fgetc(), naturellement par l'intermédiaire d'une fonction de lecture.
    Dernière modification par Invité ; 25/09/2010 à 12h53.

  13. #13
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Par défaut
    Citation Envoyé par Pierre Dolez Voir le message
    Dans votre exemple, vous faites une lecture du fichier avec fgets(). En réalité, et dans le cas général, la lecture peut être faite avec plusieurs fonctions
    Ce qui ne change pas fondamentalement les choses, toutes les fonctions de lecture ont un mécanisme similaire permettant d'indiquer qu'une erreur ou que la fin de fichier a été rencontré. Il suffit d'utiliser le test correspondant à la fonction de lecture utilisée.

    Citation Envoyé par Pierre Dolez Voir le message
    En quelque-sorte, l'instruction !feof(in) est là par sécurité et dans la pratique, un programme doit prévoir cette instruction et les instructions de lecture seront à l'intérieur de la boucle.
    Le problème c'est que simplement boucler sur feof() ne fonctionne pas. Il faut bel et bien tester le retour des fonctions de lecture. feof() permet simplement, si c'est nécessaire, de distinguer la fin de fichier d'une autre erreur de lecture.

  14. #14
    Invité
    Invité(e)
    Par défaut
    OK,
    Mais je ne sais toujours pas quand la fonction feof() peut être utilisée correctement.

  15. #15
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Par défaut
    Citation Envoyé par Pierre Dolez Voir le message
    Mais je ne sais toujours pas quand la fonction feof() peut être utilisée correctement.
    Comme dans l'exemple de Jean-Marc pour, après qu'une lecture a échouée, distinguer le cas fin de fichier des autres erreurs.

  16. #16
    Invité
    Invité(e)
    Par défaut
    Oui,
    Moi, je distingue lecture de données, contrôle de fichier, test de fin de lecture etc.
    Le fonction feof() revoie true (en fait EOF == -1) si on a atteint la fin de fichier, donc c'est une faute.
    Si on compte sur fgets() pour savoir si on a terminé, à mon avis, ce n'est pas une bonne idée. Si fgets() revoie NULL, on s'attendait à avoir une chaine et on n'en a pas. Je ne pense pas qu'il soit bon d'attendre ce test pour savoir si on fini la lecture.
    Pour moi, un retour de feof VRAI met en évidence une faute. Donc tout mon bloc de lecture est à l'intérieur d'un while(!feof()).
    Mais, vous savez, certains de mes blocs de lecture font plusieurs pages, et j'utilise très rarement fgets(), comme je ai déjà dit. Enfin, si je n'avais pas compris le fonctionnement des entrées-sorties en C, il y a probablement longtemps que je m'en serais rendu compte et que j'aurais réouvert mes bouquins .

  17. #17
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Par défaut
    Citation Envoyé par Pierre Dolez Voir le message
    Pour moi, un retour de feof VRAI met en évidence une faute. Donc tout mon bloc de lecture est à l'intérieur d'un while(!feof()).
    Et si tu rencontres une erreur de lecture qui n'est pas la fin de fichier ?
    feof() renvoie faux dans ce cas et tu vas partir en boucle infinie.

    Citation Envoyé par Pierre Dolez Voir le message
    Si on compte sur fgets() pour savoir si on a terminé, à mon avis, ce n'est pas une bonne idée. Si fgets() revoie NULL, on s'attendait à avoir une chaine et on n'en a pas. Je ne pense pas qu'il soit bon d'attendre ce test pour savoir si on fini la lecture.
    Pour faire simple, feof() indique que la fin de fichier est atteinte uniquement lorsqu'on a essayer de lire après la fin du fichier.
    Par exemple si tu viens de lire le dernier caractère d'un fichier, feof() renvoie malgré tout faux. L'appel suivant à fgetc() (ou tout autre fonction de lecture) va renvoyer une erreur de lecture et seulement à ce moment là feof() renverra bien vrai.
    Donc même à l'intérieur de la boucle feof(), il faudra bien tester le retour de fonction.

  18. #18
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Citation Envoyé par Pierre Dolez Voir le message
    Il serait intéressant de préciser une utilisation de feof() "à conseiller".
    Le principe des IO en C est de tenter l'opération et vérifier si
    elle a réussit en testant son résultat. Si elle a échoué, on
    peut alors tenter de distinguer la cause de l'échec en utilisant
    le résultat -- dans le cas de fscanf() il apporte des
    renseignements supplémentaire -- ferror() et feof().

    Il est à noter que si ferror() et feof() peuvent être vrai après
    une opération réussie -- ils indiquent alors qu'on sait que
    l'opération suivante échouera par cette cause --, les
    circonstances dans lesquelles ça arrivent sont assez rares.

    On a deux classes d'opérations d'entrée: celles ne pouvant pas
    échouer à cause d'une erreur de formatage (fgetc(), fgets(),
    fread()) et celle qui peuvent échouer à cause d'une erreur de
    formatage (fscanf()).

    Dans le cas de la première classe, une fois l'échec constaté un
    appel (au choix à ferror() ou à feof()) permet d'en déterminer la
    cause.

    Dans le cas de fscanf(), on sait quelle variable n'a pas été
    assignée. Si

    - ferror(), il y a eu une erreur d'IO pendant qu'on lisait ce qui
    était nécéssaire pour déterminer la valeur à assigner dans la
    variable et après avoir lui ce qui était nécessaire pour la
    détermination réussie de la valeur à assigner dans la variable
    précédente.

    - feof(), on a atteint la fin de fichier pendant qu'on lisait ce
    qui était nécéssaire pour déterminer la valeur à assigner dans la
    variable et après avoir lui ce qui était nécessaire pour la
    détermination réussie de la valeur à assigner dans la variable
    précédente.

    - sinon, le contenu du fichier ne correspondait pas au format
    attendu en un point antérieur à la détermination de la valeur à
    assigner dans la variable.

    (Ma formulation est un peu trop complexe à mon goût, mais les
    parties fixes dont il faut vérifier la présence, le comportement
    de l'espace et la possibilité de vérifier des formats sans
    assignation fait que la situation n'est pas simple.)

    Dans votre exemple, vous faites une lecture du fichier
    avec fgets(). En réalité, et dans le cas général, la lecture peut
    être faite avec plusieurs fonctions,
    Seul fscanf() a un comportement différent et il me semble que les
    bonnes pratiques c'est d'utiliser sscanf quand il faut utiliser
    une fonction de cette famille -- personellement, je ne l'utilise
    que rarement et bien souvent alors dans des programmes "jetables"
    pour lesquels j'ai la faiblesse de ne pas toujours être aussi
    rigoureux que je ne le suis dans un contexte de production.

    et un bonne gestion prévoira la présence d'une donnée
    marquent la fin du fichier, de façon à sortir de la bouche
    while.
    Pourquoi? Il faut être prêt à traiter une fin de fichier tout
    juste avant ce marqueur, vérifier sa présence est souvent plus
    une complication qu'autre chose.

    En prime, on maîtrise rarement le format des fichiers qu'on lit
    et une indication redondante de la fin du fichier me semble
    l'exception plutôt que la norme. Premier exemple qui vient à
    l'esprit, un fichier source C n'a pas de marqueur redondant de la
    fin du fichier.

    D'ailleurs, à titre personnel, je n'utilise fgets() que
    dans les cas où je suis sûr de l'organisation en lignes, par
    exemple un fichier CSV. C'est à dire que j'utilise fgetc(),
    naturellement par l'intermédiaire d'une fonction de
    lecture.
    fgetc() est comme fgets(), si avoir feof() vrai avant indique à
    coup sûr qu'il va y avoir une erreur de lecture, il faut quand
    même tester le résultat parce qu'il peut être EOF (NULL pour
    fgets()) à cause de la fin de fichier. Et au contraire de
    fscanf(), fgetc() ne va jamais mettre feof() à vrai sans signaler
    d'erreur de lecture.

    Citation Envoyé par Pierre Dolez Voir le message
    Le fonction feof() revoie true (en
    fait EOF == -1) si on a atteint la fin de fichier, donc c'est une
    faute.
    Tout ce qu'on sait c'est 0 ou pas.

    Si on compte sur fgets() pour savoir si on a terminé, à
    mon avis, ce n'est pas une bonne idée. Si fgets() revoie NULL, on
    s'attendait à avoir une chaine et on n'en a pas. Je ne pense pas
    qu'il soit bon d'attendre ce test pour savoir si on fini la
    lecture.
    On n'a pas le choix. Pour la plupart des fichiers et des séquences
    d'appels à des fonctions d'IO standards, on ne peut détecter la fin de
    fichier qu'après un appel qui a échoué.

    Enfin, si je n'avais pas compris le fonctionnement des
    entrées-sorties en C, il y a probablement longtemps que je m'en serais
    rendu compte et que j'aurais réouvert mes bouquins .
    Pourtant ce que tu écris rend cette hypothèse plus probable que
    l'alternative selon laquelle tu écrirais un code non idiomatique mais quand
    même correct. Le code que tu as montré jusqu'à présent ne permet pas de
    faire la différence, tout dépend de la manière dont tu traites les
    opérations d'IO qui échouent, mais

    - tu n'as pas l'air de comprendre que feof() n'a un sens qu'après une
    opération de lecture qui a échoué (dans le cas d'un fichier vide, on
    passera quand même dans ta boucle par exemple)

    - tu n'as pas l'air de comprendre que pour la plupart des fichiers et des
    séquences d'appels à des fonctions d'IO standards, feof() ne sera vrai
    qu'après une opération de lecture qui aura échoué (et donc sur le résultat
    de laquelle il ne faudra pas agir; dans le cas du fichier vide, la première
    opération d'IO échouera)

    - tu préconises une structure de fichier qui te permet d'éviter que les
    points ci-dessus te pose problème (du moins tant que tes fichiers sont
    correctement formés).

  19. #19
    Invité
    Invité(e)
    Par défaut
    Bonjour,
    J'ai tout lu, mais je ne répondrai qu'à ceci.
    En prime, on maîtrise rarement le format des fichiers qu'on lit
    et une indication redondante de la fin du fichier me semble
    l'exception plutôt que la norme. Premier exemple qui vient à
    l'esprit, un fichier source C n'a pas de marqueur redondant de la
    fin du fichier.
    L' exemple du fichier source C est intéressant, mais je ne sais pas si beaucoup de logiciels, à part les compilateurs ont à lire de tels fichiers.
    Comme exemple, j'aurais plutôt pris le format CSV, ou des fichiers log.
    Je prend aussi l'exemple de fichiers dont on ignore tout et que l'on lit en Hexa et en Ascii, pour essayer de les décoder.
    Mais les fichier que j'ai plus l'occasion de lire sont bien organisés, type DXF, SHP,XML etc.
    Mais je suis d'accord pour tout, je n'ai pas compris la gestion de fichier en C. D'ailleurs, je suis encore débutant.
    Par contre, je crois que je connais assez bien la logique de développement.

Discussions similaires

  1. Problème d'exécution aléatoire et inconnu
    Par en_gel_ho dans le forum Access
    Réponses: 2
    Dernier message: 15/12/2006, 12h57
  2. [DOM] Problème de traitement récursif, nombre de noeuds fils
    Par erivoil dans le forum Bibliothèques et frameworks
    Réponses: 2
    Dernier message: 13/12/2006, 12h39
  3. Problème de traitement d'image tiff
    Par Galkir dans le forum C++Builder
    Réponses: 2
    Dernier message: 29/06/2006, 09h05
  4. Problème de traitement de file
    Par Bouguennec dans le forum Langage
    Réponses: 3
    Dernier message: 09/05/2006, 17h57
  5. Problème avec traitement de chaînes
    Par cortex007 dans le forum Langage
    Réponses: 6
    Dernier message: 25/04/2006, 16h22

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo