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 :

Fonction de lecture dans un fichier, et problème avec strchr


Sujet :

C

  1. #1
    Futur Membre du Club
    Inscrit en
    Octobre 2002
    Messages
    9
    Détails du profil
    Informations forums :
    Inscription : Octobre 2002
    Messages : 9
    Points : 5
    Points
    5
    Par défaut Fonction de lecture dans un fichier, et problème avec strchr
    J'ai écrit cette fonction, tout est décrit dans le code:

    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
    38
    39
    40
    41
     
    char* LireLigneFichier(char *lecture, int taille, FILE *pf)  
    /* Cette fonction place dans "lecture" une chaîne de "taille" caractères, 
       à partir d'une ligne du fichier "pf".
       Si la longueur de la ligne est supérieure à "taille", seulement les "tailles"
       premiers caractères de la ligne sont placé dans "lecture", et le reste 
       de la ligne est ignoré. 
       En revanche la lecture suivante sera effectuée sur la ligne suivante, 
       on pourra ainsi lire cette nouvelle ligne sans problème due au reste 
       de la ligne précédente.
       Retourne NULL si rien n'a été lu. */
    {
        char *temp=NULL;
        char *res;
        char buffer[1024]; /* "buffer" est utilisée pour lire une ligne entière 
                              du fichier.
                              Cette fonction peu lire au maximum des lignes de 
                              "1024-'\n'-1" caractères. */
     
        res=fgets(buffer, sizeof(buffer), pf); /* place la ligne lu dans 
                                                  buffer ('\n' inclut), d'une taille
                                                  de sizeof(buffer)-1 carac.
                                                  retourne NULL si rien n'a été lu */
                                               /* exemple de lecture: "abc\n\0" */
     
        temp=strchr(buffer, '\n'); /* recherche la ou se trouve le '\n' */
     
        if(temp!=NULL)
            *temp='\0'; /* écrasement du '\n'.
           	               exemple: "abc\n\0" devient "abc\0\0" */
                       	 /* note: sous linux(gcc) il faut mettre *(temp-1)='\0'
     	                         sous dev-c++(gcc) *temp='\0' */
     
        strncpy(lecture, buffer, taille);
        lecture[taille-1]='\0'; /* car si la taille de "buffer" est >= à "taille", 
                                   alors il n'y aura pas de '\0' terminal dans 
                                   "lecture".
                                   Donc on écrase le dernier caractére avec '\0' */
     
        return res;
    }
    Je voudrais déjà avoir votre avis sur cette fonction, et aussi sur le problème de la différence de comportement entre linux et windows (j'y fait référence dans les commentaires), je pense que le problème se situe au niveau du strchr...

  2. #2
    Responsable technique

    Avatar de Anomaly
    Homme Profil pro
    Directeur
    Inscrit en
    Juin 2003
    Messages
    10 338
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Somme (Picardie)

    Informations professionnelles :
    Activité : Directeur
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Juin 2003
    Messages : 10 338
    Points : 130 370
    Points
    130 370
    Billets dans le blog
    1
    Par défaut
    Bonsoir,
    Je pense que ton problème vient des fins de lignes différentes des fichiers textes sous Unix et Windows.

    Sous Unix, une ligne se termine par un \n
    Sous Windows, une ligne se termine par \r \n (une horreur qui a une origine historique).

    Si tu ouvres un fichier en mode texte sous Windows (c'est le mode par défaut, pas de "b" dans le fopen), il se charge d'éliminer les \r à la lecture et les mettre en écriture, afin que pour le programme, le fichier "semble" être au format Unix, ce qui assure la compatibilité. Sous Linux, le mode texte ne change rien.

    Ici, tu as le problème contraire : mais je pense que ça vient directement de ton fichier d'entrée. Ton fichier d'entrée doit être au format DOS et avoir ses lignes terminées car \r \n. Windows les élimine automatiquement car c'est son format normal, mais Linux lui ne s'attend pas à de telles terminaisons et donc il te les laisse.

    Ton problème n'est donc pas lié à ton programme mais à ton fichier d'entrée. Des outils comme dos2unix et unix2dos servent à convertir un type de fichier texte d'un système à l'autre.

    Si tu ouvres avec Emacs Linux un fichier texte au format DOS, il sera marqué tel quel dans la barre d'état (et Emacs Windows marquera dans la barre d'état si un fichier texte est au format Unix).

    Evidemment la seule syntaxe bonne est
    Responsable technique forum & site

    Si ce message (ou un autre) vous a aidé et/ou vous semble pertinent, votez pour lui avec

  3. #3
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut Re: Fonction de lecture dans un fichier, et problème avec st
    Citation Envoyé par neird
    J'ai écrit cette fonction, tout est décrit dans le code:

    <...>
    Je voudrais déjà avoir votre avis sur cette fonction, et aussi sur le problème de la différence de comportement entre linux et windows (j'y fait référence dans les commentaires), je pense que le problème se situe au niveau du strchr...
    A la lumière des reflexions d'Anomaly, j'en déduis que la différence de comportement vient de ce que le fichier est probablement ouvert en mode binaire ("rb") alors qu'il devrait l'être en mode texte ("r")..

    Dans ce cas, ce code (pas besoin de chaine intermédiaire) ...
    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
     
    #include <stdio.h>
    #include <string.h>
     
    char* LireLigneFichier (char *lecture, int taille, FILE *pf)  
    {
       char *res = fgets (lecture, taille, pf);
     
       if (res != NULL)
       {
          char *p = strchr (buffer, '\n');
     
          if (p != NULL)
          {
             *p = 0;
          }
          else
          {
             /* prendre les mesures qui s'imposent 
              * (tronquer, lire la suite etc.) 
              */
          }
       }
       return res;
    }
    ... est portable à condition que le fichier lu ait été créé par le même système. En effet, le format des fichiers textes diffère d'un système à l'autre :
    (sauf erreur ou omission de ma part) :
    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
     
    :----------------:--------------:----------------:
    : Système        : Fin de ligne : Fin de fichier :
    :----------------:--------------:----------------:
    : Unix           :              :                :
    : Mac X          : 0x0A LF      : Sans objet     :
    : Linux          :              :                :
    :----------------:--------------:----------------:
    : Mac (non unix) : Ox0D CR      : Sans objet     :
    :----------------:--------------:----------------:
    : MS-DOS         : Ox0D 0x0A    : 0x1A           :
    : Windows        : CR LF        : ^Z             :
    : Windows NT     :              :                :
    :----------------:--------------:----------------:
    : VMS STREAM_CR  : Ox0D CR      : Sans objet     :
    :----------------:--------------:----------------:
    : VMS STREAM_LF  : 0x0A LF      : Sans objet     :
    :----------------:--------------:----------------:
    : VMS STREAM_CRLF: Ox0D 0x0A    : Sans objet     :
    :----------------:--------------:----------------:
    Mais si on doit lire sur une machine Linux un fichier texte créé par une machine MS-DOS ou Mac, ou inversement, le comportement est indéfini. Détails dans le post d'Anomaly.
    Pas de Wi-Fi à la maison : CPL

  4. #4
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par Anomaly
    Sous Windows, une ligne se termine par \r \n (une horreur qui a une origine historique).
    Ce n'est pas vraiment une horreur, vu que c'est exactement ce qu'il faut envoyer à un périphérique en mode 'raw' (Telétype, imprimante matricielle) pour faire ce qu'il faut :

    CR : retour de la tête d'impression en colonne 1.
    LF : Avancer le papier d'une ligne.

    Si on ne fait que CR (Mac), on va écrire tout sur la même ligne (pas terrible...)
    Si on ne fait que LF (Unixoides), on va décaler d'une ligne, mais sans revenir en colonne 0. On ira pas loin!
    Sur une console, c'est pareil avec le curseur et le scrolling.

    En langage C (et on voit bien l'influence d'Unix sur ce point), il a été décidé que '\n' serait le caractère de fin de ligne quelle que soit le système. C'est bien pour la portabilité (la conversion est automatique en mode cooked, càd texte), mais ça peut être assez troublant si on passe en mode raw (binaire) sur certains systèmes.
    Pas de Wi-Fi à la maison : CPL

  5. #5
    Responsable technique

    Avatar de Anomaly
    Homme Profil pro
    Directeur
    Inscrit en
    Juin 2003
    Messages
    10 338
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Somme (Picardie)

    Informations professionnelles :
    Activité : Directeur
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Juin 2003
    Messages : 10 338
    Points : 130 370
    Points
    130 370
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Emmanuel Delahaye
    Citation Envoyé par Anomaly
    Sous Windows, une ligne se termine par \r \n (une horreur qui a une origine historique).
    Ce n'est pas vraiment une horreur, vu que c'est exactement ce qu'il faut envoyer à un périphérique en mode 'raw' (Telétype, imprimante matricielle) pour faire ce qu'il faut :

    CR : retour de la tête d'impression en colonne 1.
    LF : Avancer le papier d'une ligne.
    Oui, je sais bien pourquoi cela est ainsi. C'est pour ça que je parle d'origine historique.

    D'ailleurs, la console DOS fonctionne suivant le même principe : \r ramène en début de ligne et \n saute la ligne sans ramener au début de ligne.

    Ce qui me fait dire que c'est une horreur, c'est :
    a) le principe de terminaison des lignes par 2 caractères, et
    b) le fait que cela soit différent selon le système

    Comme tu le dis fort justement, sous Mac seul le caractère CR est envoyé. Maintenant il faut admettre ces différences et faire avec.
    Responsable technique forum & site

    Si ce message (ou un autre) vous a aidé et/ou vous semble pertinent, votez pour lui avec

  6. #6
    Futur Membre du Club
    Inscrit en
    Octobre 2002
    Messages
    9
    Détails du profil
    Informations forums :
    Inscription : Octobre 2002
    Messages : 9
    Points : 5
    Points
    5
    Par défaut Re: Fonction de lecture dans un fichier, et problème avec st
    Merci à vous, j'ai bien compris le problème des fins de lignes.
    Et effectivement, ce sont les fichiers générés sous windows qui se révélent illisible avec cette fonction sous linux.
    Maintenant je voudrais revenir sur cette fonction proposé:

    Citation Envoyé par Emmanuel Delahaye

    Dans ce cas, ce code (pas besoin de chaine intermédiaire) ...
    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
     
    #include <stdio.h>
    #include <string.h>
     
    char* LireLigneFichier (char *lecture, int taille, FILE *pf)  
    {
       char *res = fgets (lecture, taille, pf);
     
       if (res != NULL)
       {
          char *p = strchr (buffer, '\n');
     
          if (p != NULL)
          {
             *p = 0;
          }
          else
          {
             /* prendre les mesures qui s'imposent 
              * (tronquer, lire la suite etc.) 
              */
          }
       }
       return res;
    }
    Le problème est que si par exemple je lis une chaine de 10 carac (LireLigneFichier(c, 10, f)), si par n'importe quel hasard, la ligne que je lis fait plus de 10 caractères, alors à la lecture suivante(des 10carac suivants), je lirais la fin de la ligne. Or je préferes passer à la ligne suivante et ignorer la fin de la ligne précédente. C'est pour cela que j'utilise une variable intermédiaire buffer, ainsi je suis "sur" de lire entièrement la ligne.
    Je sais pas si c'est très clair...

  7. #7
    Rédacteur/Modérateur
    Avatar de Trap D
    Profil pro
    Inscrit en
    Septembre 2003
    Messages
    4 942
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2003
    Messages : 4 942
    Points : 6 498
    Points
    6 498
    Par défaut
    C'est clair, et n'oublie pas qu'il faut faire une boucle de lecture jusqu'à ce que la recherche du '\n' renvoie un pointeur non NULL.
    "La haine seule fait des choix" - Koan Zen
    "Il ne faut pas être meilleur que les autres, il faut être meilleur que soi." Albert Jacquard
    "Ceux qui savent où ils ont posé leur parapluie ne sont pas alcooliques." - pgibonne.
    Faites du Prolog, ça vous changera les idées !
    Ma page Prolog
    Mes codes sources commentés

    Mon avatar : La Madeleine à la veilleuse de Georges de La Tour

  8. #8
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut Re: Fonction de lecture dans un fichier, et problème avec st
    Citation Envoyé par neird
    Merci à vous, j'ai bien compris le problème des fins de lignes.
    Et effectivement, ce sont les fichiers générés sous windows qui se révélent illisible avec cette fonction sous linux.
    Maintenant je voudrais revenir sur cette fonction proposé:

    <...>

    Le problème est que si par exemple je lis une chaine de 10 carac (LireLigneFichier(c, 10, f)), si par n'importe quel hasard, la ligne que je lis
    Ce n'est pas du 'hasard'. Il est tout à fait possible que la ligne à lire fasse plus de 10 caractères. Le cas est prévu dans le 'else'. Simplement, je te laisse faire le traitement que tu veux. Pour tronquer, il suffit de lire tous les caractères jusqu'au prochain '\n' ou EOF.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
       else
       {
          /* ignorer la suite de la ligne */
          int c;
          while ((c = fgetc(pf)) != '\n' && c != EOF)
          {
          }
       }
    fait plus de 10 caractères, alors à la lecture suivante(des 10carac suivants), je lirais la fin de la ligne. Or je préferes passer à la ligne suivante et ignorer la fin de la ligne précédente. C'est pour cela que j'utilise une variable intermédiaire buffer, ainsi je suis "sur" de lire entièrement la ligne.
    Je sais pas si c'est très clair...
    Moyennement, en tout cas, je le confirme, la chaine intermédiaire est inutile.
    Pas de Wi-Fi à la maison : CPL

  9. #9
    Membre habitué
    Inscrit en
    Juin 2004
    Messages
    165
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 165
    Points : 136
    Points
    136
    Par défaut
    J'aimerais comprendre :

    On me dit que "\r\n" sous windows
    On me dit que "\n" sous Linux

    Je vous crois mais pourquoi dans un programme compilé et executé sous windows j'ai ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    char ligne[70];
     
    fgets(ligne,sizeof(ligne),fichier);
    if (strcmp(ligne,"var1\n")==0) printf("OK");
    Affichage de "OK"

    Mais lorsque je compile et exécute sous Linux seul ce code m'affiche "OK":

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    char ligne[70];
     
    fgets(ligne,sizeof(ligne),fichier);
    if (strcmp(ligne,"var1\r\n")==0) printf("OK");

  10. #10
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par n00bi
    J'aimerais comprendre :

    On me dit que "\r\n" sous windows
    On me dit que "\n" sous Linux
    Exact. Ce sont les valeurs réelles dans le fichier. Ces valeur sont accessibles en mode binaire.

    En mode texte, on ne voit que '\n' quelque soit le système si le fichier texte a été ecrit avec le même système. Si on transfert un fichier texte d'un système à l'autre, une conversion est peut être nécessaire.

    Je rappelle l'existence des utilitaires dos2unix et unix2dos pour la conversion des fichiers textes dans les deux environnements.
    Je vous crois mais pourquoi dans un programme compilé et executé sous windows j'ai ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    char ligne[70];
     
    fgets(ligne,sizeof(ligne),fichier);
    if (strcmp(ligne,"var1\n")==0) printf("OK");
    Affichage de "OK"

    Mais lorsque je compile et exécute sous Linux seul ce code m'affiche "OK":

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    char ligne[70];
     
    fgets(ligne,sizeof(ligne),fichier);
    if (strcmp(ligne,"var1\r\n")==0) printf("OK");
    Ca dépend si le fichier est ouvert en mode texte ou binaire
    Ca dépend si le fichier texte a été ecrit sous DOS ou sous Windows.

    Il faut fournir les conditions de test exactes.
    Pas de Wi-Fi à la maison : CPL

  11. #11
    Membre habitué
    Inscrit en
    Juin 2004
    Messages
    165
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 165
    Points : 136
    Points
    136
    Par défaut
    Donc tu me dis que mon prog ne marchera pas de la meme maniere si le fichier est créé sous Linux ( en l'occurence j'avais créé mon fichier sous Windows ) ?

    Pb c'est l'utilisateur qui dl mon prog et qui lui passe son propre fichier en parametre. Et je sais pas a l'avance s'il a été créé sous windows ou sous Linux ... C'est quand même nul les deux fins de lignes différentes sous les deux OS.

  12. #12
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par n00bi
    Donc tu me dis que mon prog ne marchera pas de la meme maniere si le fichier est créé sous Linux ( en l'occurence j'avais créé mon fichier sous Windows ) ?
    Ni sous Mac pour lequel le séparateur est encore different (CR), ni sous VAX...

    Pb c'est l'utilisateur qui dl mon prog et qui lui passe son propre fichier en parametre. Et je sais pas a l'avance s'il a été créé sous windows ou sous Linux ... C'est quand même nul les deux fins de lignes différentes sous les deux OS.
    Bah, sur mainframe IBM, le codage des caractères est différent de ASCII... Alors ces petits détails sont sans importance. Comme je te l'ai déjà dit des utilitaires de conversions sont livrés avec les OS (ou faciles à faire). C'est aussi à l'utilisateur de savoir ce qu'il fait...

    C'est un problème archi connu. Un éditeur comme UltraEdit (Windows) sait importer des fichiers au format unix et les convertir si nécessaire (ou les laisser au format unix).

    En principe, sur le réseau, les fichiers textes sont au format 'unixoide' (LF)
    Pas de Wi-Fi à la maison : CPL

  13. #13
    Membre habitué
    Inscrit en
    Juin 2004
    Messages
    165
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 165
    Points : 136
    Points
    136
    Par défaut
    Merci de toutes ses précisions !

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 4
    Dernier message: 05/02/2014, 11h01
  2. Réponses: 1
    Dernier message: 16/03/2010, 09h58
  3. problème de lecture dans un fichier
    Par phy4me dans le forum Fortran
    Réponses: 1
    Dernier message: 20/05/2007, 20h55
  4. Problème de lecture dans un fichier xml
    Par Pyra dans le forum Langage
    Réponses: 2
    Dernier message: 18/12/2005, 00h13
  5. Réponses: 20
    Dernier message: 25/09/2005, 15h07

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