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 :

Lecture d'un fichier octet par octet


Sujet :

C

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    200
    Détails du profil
    Informations personnelles :
    Localisation : France, Bas Rhin (Alsace)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 200
    Points : 89
    Points
    89
    Par défaut Lecture d'un fichier octet par octet
    Bonjour,
    Je souhaitrais savoir quel est le moyen le plus efficace pour lire un fichier octet par octet (pour calculer un checksum).

    ce qui parait le simple, c'est :

    - fopen()
    - fread() de 1 octet jusqu'à EOF
    - fclose()

    Sachant que le fichier est sur une mémoire de masse, est ce que le fopen() va tout copier en RAM ?
    Est ce que la fonction fread est une fonction "lente" ?
    Est-il plus efficace de de lire tout le fichier d'un coup (quid de la récupération sa taille...) et de le placer dans un char* avant de manipuler cette variable ?

    Merci d'avance pour vos avis.

    PS : développement sur un OS type UNIX

    Nicolas

  2. #2
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 209
    Points
    23 209
    Par défaut
    Tu peux déjà utiliser les fonctions open, read et close au lieu de fopen, fread et fclose pour être plus rapide.

    Pour fopen, il ne me semble pas qu'il copie tout en RAM mais qu'il copie le(s) partie(s) du fichiers sur lequel tu travaille actuellement (à vérifier tout de même)

    Tu peux en effet lire ton fichier d'un coup je pense que ce sera plus pratique et rapide. Dans ce cas là pour récupérer la taille de ton fichier, utilise struct stat de sys/stat.h

  3. #3
    Membre émérite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2008
    Messages
    1 515
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 515
    Points : 2 505
    Points
    2 505
    Par défaut
    Au contraire, si tu fais des lectures octet par octet fopen/fread sera beaucoup plus rapide que open/read puisque les lectures sont bufferisées.

    Effectivement fread charge le fichier par morceaux. On peut changer la taille du buffer avec setvbuf().

    L'autre option, c'est de mapper le fichier en mémoire avec mmap(). C'est plus simple et potentiellement plus efficace si tu dois faire des accès aléatoires. Si tu lis le fichier séquentiellement, ça ne change pas grand chose.

  4. #4
    Membre éclairé
    Inscrit en
    Décembre 2010
    Messages
    290
    Détails du profil
    Informations forums :
    Inscription : Décembre 2010
    Messages : 290
    Points : 719
    Points
    719
    Par défaut
    Au contraire, si tu fais des lectures octet par octet fopen/fread sera beaucoup plus rapide que open/read puisque les lectures sont bufferisées
    En effet, fopen cause une bufferisation du fichier, que open ne fait pas (du moins par défaut).
    Mais une fois fopen appelée, lire le fichier octet par octet peut se faire simplement avec fgetc(), qui utilisera le buffer créé par fopen. C'est plus simple que d'utiliser fread.

  5. #5
    Membre régulier
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    200
    Détails du profil
    Informations personnelles :
    Localisation : France, Bas Rhin (Alsace)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 200
    Points : 89
    Points
    89
    Par défaut
    Voici ce que j'ai pour le moment :

    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
    UINT16 CRC_File(const char* szPath)
    {
    	FILE* fichier ;
    	char c ;
     
    	UINT8 j = 0 ;
    	UINT16 usCRCWord = 0;
    	UINT16 usPoly = 0x8408;
    	UINT8 bParite=0 ;
     
     
    	fichier = fopen(szPath,"r") ;
    	if(0!=fichier)
    	{
    		while(feof(fichier)==0)
    		{
    			fread(&c,1,1,fichier) ;
     
    			usCRCWord^=c;
    			for(j=0;j<8;j++)
    			{
    				if(usCRCWord & 1)
    					bParite=0;
    				else
    					bParite=1;
    				usCRCWord>>=1;
    				if(!bParite)
    					usCRCWord^=usPoly;
    			}
     
    		}
     
    		fclose(fichier) ;
    	}
    	return usCRCWord ;
    }
    Donc si j'ai bien compris, mieux vaut utiliser une variable intermédiaire (const char*) et appeler une seule fois la fonction fread().

    Dans ce cas, je suis obligé de passer par un malloc() pour créer mon buffer.

    Correct ?

  6. #6
    Membre régulier
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    200
    Détails du profil
    Informations personnelles :
    Localisation : France, Bas Rhin (Alsace)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 200
    Points : 89
    Points
    89
    Par défaut
    Citation Envoyé par phi1981 Voir le message
    Mais une fois fopen appelée, lire le fichier octet par octet peut se faire simplement avec fgetc(), qui utilisera le buffer créé par fopen. C'est plus simple que d'utiliser fread.
    Pourquoi plus simple ?
    fgetc() n'est pas à utiliser que pour de l'ascii ?

  7. #7
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2011
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2011
    Messages : 25
    Points : 68
    Points
    68
    Par défaut
    Salut,

    Mais une fois fopen appelée, lire le fichier octet par octet peut se faire simplement avec fgetc(), qui utilisera le buffer créé par fopen. C'est plus simple que d'utiliser fread.
    Juste pour dire, parce que la phrase est ambiguë, la fonction fread utilise également le tampon alloué par fopen. De manière générale, toute les fonctions standard de traitement de flux utilisent le tampon associé à un flux (lorsqu'il en a un).

    fgetc() n'est pas à utiliser que pour de l'ascii ?
    Non, étant donné qu'un flux binaire n'est qu'une suite ordonnée de byte (char), il est tout à fait possible de lire chacun d'entre eux à l'aide de fgetc.

    Sinon, pour répondre à la question, la bonne solution me semble d'ouvrir le fichier en mode binaire ("rb") et d'effectuer la lecture par bloc de taille BUFSIZ. Autrement dit, de remplir un tableau de unsigned char de taille BUFSIZ à l'aide de fread et de parcourir ensuite ce dernier caractère par caractère pour effectuer la somme.

    L'autre option, c'est de mapper le fichier en mémoire avec mmap(). C'est plus simple et potentiellement plus efficace si tu dois faire des accès aléatoires. Si tu lis le fichier séquentiellement, ça ne change pas grand chose.
    Tu peux en effet lire ton fichier d'un coup je pense que ce sera plus pratique et rapide. Dans ce cas là pour récupérer la taille de ton fichier, utilise struct stat de sys/stat.h
    Je doute que ces deux solutions soient plus rapide qu'une lecture par bloc étant donné qu'elles impliquent une allocation dynamique potentiellement importante (voir irréalisable si le fichier est trop volumineux).

  8. #8
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 360
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 360
    Points : 23 600
    Points
    23 600
    Par défaut
    Hello,

    Citation Envoyé par Nico_stras Voir le message
    Pourquoi plus simple ?
    fgetc() n'est pas à utiliser que pour de l'ascii ?
    Non. fgetc() va te renvoyer un unsigned char dans le sens C du terme, transtypé en INT pour pouvoir éventuellement te renvoyer EOF. C'est assurément ce qu'il y a de plus simple ici.

  9. #9
    Membre régulier
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    200
    Détails du profil
    Informations personnelles :
    Localisation : France, Bas Rhin (Alsace)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 200
    Points : 89
    Points
    89
    Par défaut
    Citation Envoyé par Taurre Voir le message
    Sinon, pour répondre à la question, la bonne solution me semble d'ouvrir le fichier en mode binaire ("rb") et d'effectuer la lecture par bloc de taille BUFSIZ. Autrement dit, de remplir un tableau de unsigned char de taille BUFSIZ à l'aide de fread et de parcourir ensuite ce dernier caractère par caractère pour effectuer la somme.
    BUFSIZ est une constante définie dans un header ?

    Comment implémenter cette lecture par bloc ?
    Lire 1 bloc, le traiter, puis lire un autre bloc, plus le traiter ?

    Aurais-tu un petit bout de pseudo-code?

  10. #10
    Expert éminent sénior
    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
    Points : 13 926
    Points
    13 926
    Par défaut
    En suivant la trame :
    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
    #include <stddef.h>
    #include <stdio.h>
    ....
    #define BUFSIZE ....
    unsigned char buf[BUFSIZE];
    size_t n;
    f = fopen(..., "rb");
    if(f!=NULL)
    {
      do
      {
        n = fread(buf,1,BUFSIZE,f);
        /* traiter les n premières valeurs du tableau buf */
       }while(n== BUFSIZE);
      if(feof(f)) printf("lecture terminée");
      else printf("erreur de lecture");
      fclose(f);
    }
    Publication : Concepts en C

    Mon avatar : Glenn Gould

    --------------------------------------------------------------------------
    Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !

  11. #11
    Membre régulier
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    200
    Détails du profil
    Informations personnelles :
    Localisation : France, Bas Rhin (Alsace)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 200
    Points : 89
    Points
    89
    Par défaut
    quelle est la valeur de BUFSIZE ?
    Si j'ai des fichiers pouvant atteindre 10 Mo ?

  12. #12
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2011
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2011
    Messages : 25
    Points : 68
    Points
    68
    Par défaut
    Désolé pour cette réponse tardive.

    Citation Envoyé par Nico_stras Voir le message
    BUFSIZ est une constante définie dans un header ?
    Oui, elle est définie dans l'en-tête <stdio.h>, tu n'as donc pas à te préoccuper de sa valeur

  13. #13
    Membre régulier
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    200
    Détails du profil
    Informations personnelles :
    Localisation : France, Bas Rhin (Alsace)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 200
    Points : 89
    Points
    89
    Par défaut
    Je ne comprends pas ce code :

    Citation Envoyé par diogene Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    ...
      do
      {
        n = fread(buf,1,BUFSIZE,f);
        /* traiter les n premières valeurs du tableau buf */
       }while(n== BUFSIZE);
      if(feof(f)) 
         printf("lecture terminée");
      else 
         printf("erreur de lecture");
    pourquoi ?

    Pourquoi unr erreur si on est pas à la fin du fichier ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
      if(feof(f)) 
         printf("lecture terminée");
      else 
         printf("erreur de lecture");

  14. #14
    Expert éminent sénior
    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
    Points : 13 926
    Points
    13 926
    Par défaut
    fread() renvoie le nombre d'éléments lus. On lui a demandé d'en lire BUFSIZE. Si il en a lu moins, c'est que - soit il a atteint la fin du fichier et il n'y avait plus rien à lire,- soit il y a eu une erreur de lecture sur le fichier. Les deux cas peuvent se distinguer par la fonction feof() (ou ferror()). Si on est sûr que le deuxième cas ne peut se produire, le test est inutile et on sort de la boucle sur la fin de fichier.
    Publication : Concepts en C

    Mon avatar : Glenn Gould

    --------------------------------------------------------------------------
    Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !

  15. #15
    Membre régulier
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    200
    Détails du profil
    Informations personnelles :
    Localisation : France, Bas Rhin (Alsace)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 200
    Points : 89
    Points
    89
    Par défaut
    Sachant que BUFSIZE est une constante

    que se passe-t-il si la taille du fichier est inférieure ? appels de fread inutilement ? erreurs ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
      if(feof(f)) 
         printf("lecture terminée");
      else 
         printf("erreur de lecture");
    que se passe-t-il si la taille du fichier est supérieure ? Il faut reboucler ?


    A la place de faire un fread d'un octet, il est possible de faire un fread de BUFSIZE octes, puis de boucler dans la chaine de caractères obtenue.
    Quelle serait la différence ?

    Merci

  16. #16
    Membre émérite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2008
    Messages
    1 515
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 515
    Points : 2 505
    Points
    2 505
    Par défaut
    La différence est qu'en lisant tout un bloc d'un coup tu as mois d'appels de fonctions (fread), ce qui peux être très légèrement plus efficace.

    Diogène a déjà répondu à tes deux 1ères questions. Si la taille du fichier est plus petite que BUFSIZE, alors la 1ère lecture sortira de la boucle où feof() indiquera la fin du fichier. Si le fichier est plus gros, alors on fait plusieurs tours de boucles puisque fread() renverra BUFSIZE tant qu'on n'arrive pas à la fin du fichier.

    En passant, BUFSIZE est juste la taille par défaut du buffer de la libc. Rien ne t'oblige à lire des blocs de BUFSIZE. Rien ne te garantie non plus que la libc lit par blocs de BUFSIZE. D'ailleurs que je sache BUFSIZE n'est pas une macro standard, elle peut très bien ne pas être définie.

  17. #17
    Membre régulier
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    200
    Détails du profil
    Informations personnelles :
    Localisation : France, Bas Rhin (Alsace)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 200
    Points : 89
    Points
    89
    Par défaut
    ok, je comprends mieux.
    Je croyais que la fonction
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    n = fread(buf,1,BUFSIZE,f);
    renvoyait 1 caractère.

    Quel est le rôle du 2ème arguement, sachant que c'est BUFSIZE qui défini le nombre d'octets lus ?

    Comment est défini BUFSIZE ? Est ce que la valeur est modifiable ou est directement dépendante de la plateforme ?

  18. #18
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 678
    Points
    13 678
    Billets dans le blog
    1
    Par défaut
    Il suffit de constater le manuel de la fonction : http://man.developpez.com/man3/fread.3.php

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    size_t fread (void *ptr, size_t size, size_t nmemb, FILE *stream);
    La fonction fread lit nmemb éléments de données, chacun d'eux représentant size octets de long, depuis le flux pointé par stream, et les stocke à l'emplacement pointé par ptr.
    Ton fread lit pas BUFSIZE octets parce que le deuxième argument vaut 1 (1 octet).

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

Discussions similaires

  1. Lecture d'un fichier .wav octet par octet
    Par DevVB dans le forum VB 6 et antérieur
    Réponses: 7
    Dernier message: 27/07/2007, 13h10
  2. [Java 1.4] : lecture d'un fichier octet par octet
    Par Thi0123 dans le forum Entrée/Sortie
    Réponses: 10
    Dernier message: 08/06/2007, 22h29
  3. [Gestion de fichiers] Lecture octet par octet
    Par kendras dans le forum C
    Réponses: 21
    Dernier message: 18/09/2006, 16h08
  4. Lecture d'un fichier octet par octet
    Par Yux dans le forum C
    Réponses: 7
    Dernier message: 31/10/2005, 23h58
  5. Lecture d'un fichier octet par octet
    Par PopKoRn...X_x dans le forum C++
    Réponses: 10
    Dernier message: 01/07/2005, 20h09

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