Lecture et écriture de fichiers en mode binaire

Formation

En Ligne

Prix sur demande

Appeler le centre

Avez-vous besoin d'un coach de formation?

Il vous aidera à comparer différents cours et à trouver la solution la plus abordable.

Description

  • Typologie

    Formation

  • Méthodologie

    En ligne

Grâce à cette formation vous pourrez acquérir les connaissances nécessaires qui vous permettrons d’ajouter des compétences à votre profil et obtenir de solides aptitude qui vous offriront de nombreuses opportunités professionnelles.

Questions / Réponses

Ajoutez votre question

Nos conseillers et autres utilisateurs pourront vous répondre

À qui souhaitez-vous addresser votre question?

Saisissez vos coordonnées pour recevoir une réponse

Nous ne publierons que votre nom et votre question

Les Avis

Les matières

  • Écriture
  • Lecture

Le programme

Introduction du cours

Comme ce que vous avez pu voir dans le cours de M@teo21 sur l'écriture et la lecture d'un fichier, si ce n'est pas encore fait, alors je vous le conseille vivement avant de continuer à lire ce présent tutoriel :) , on peut écrire et lire dans un fichier au format texte (ASCII). Ici je vais vous parler d'une autre méthode de lecture et écriture non formatée qu'on appelle écriture binaire.

En vous souhaitant bonne lecture.

Le mode formaté et non formatéprintf () et le mode formaté

Je vais parler un peu de printf :) , et oui ça vous rappelle quelque chose (enfin je l'espère :p ).

Cette merveilleuse fonction qui se tape un grand travail afin de nous afficher les choses qu'on lui donne au format qu'on désire, et ceci en mode dit "formaté", c'est-à-dire, que la donnée que nous lui avons passée sera écrite d'une façon personnalisée et au format ASCII.

int var = 15; printf("la valeur de var est %d",var);

Ainsi, la valeur de la variable var , sera inscrite en caractères ASCII ('1' et '5') sur l'écran.

la valeur de var est 15La différence entre fwrite et printf

Maintenant que nous savons un peu ce qu'est l'écriture en mode formaté, voyons ce que c'est qu'un mode dit "non formaté". En l'occurrence le mode d'écriture de fwrite.

Vous avez dû lire dans le cours de M@teo21 que quand on déclare une variable, cela alloue une place dans la mémoire pour contenir ce qu'on va stocker dans cette variable.

Je m'explique :)

Si je continue sur l'exemple d'avant, une déclaration comme ceci :

int var;

Va allouer un espace qu'on nommera 'var', ainsi si on lui affecte une valeur, cette valeur sera inscrite dans cet espace mémoire, qui, dans le cas d'un int, est généralement sur 4 octets (32 bits).

La notions de bits est importante ici :) .

Ainsi le résultat d'une affectation comme ceci :

int var = 15;

Donnerait en mémoire :

00000000

00000000

00000000

00001111

Qui est la représentation binaire du nombre 15 sur 32 bits. J'ouvre une parenthèse pour vous informer que l'ordre de ces 4 octets peut différer d'une machine à l'autre selon le codage utilisé (Endianess). Je vais donc vous demander de supposer qu'on est sur une machine utilisant ce codage :) (ce sera transparent pour la suite, du temps qu'on ne change pas de machine).

C'est quoi le rapport avec fwrite ?

fwrite est une fonction qui se fiche de la valeur enregistrée dans notre variable var, contrairement à printf qui pour afficher '1' et '5' a dû évaluer cette valeur binaire en décimale.
La variable 'var' pour la fonction fwrite sera ni plus ni moins qu'une suite d'octets en mémoire, une utilisation de cette dernière va inscrire dans un fichier les octets représentant notre variable en mémoire.

Si je continue sur l'exemple, la fonction fwrite inscrira ceci dans le fichier :

octet1 - octet2 - octet3 - octet4

00000000 00000000 00000000 00001111

Qui représente notre espace mémoire 'var' contenant la valeur 15.

Avantages de fwrite par rapport à fprintf

L'avantage que fwrite peut avoir par rapport à fprintf, est la simplicité de l'écriture et encore plus, de la lecture :) . Pour mettre ceci en évidence je vais prendre l'exemple d'une structure.

Si j'ai la structure suivante :

typedef struct { int age; char nom[30]; char prenom[30]; char adresse[60]; int nombreFreres; }SPersonne ; SPersonne personne; //Je déclare une variable de type SPersonne

Et que je souhaite sauvegarder les données relatives à une personne que j'ai créée. Avec fprintf, je vais être obligé d'écrire champ par champ :-° alors que avec fwrite une seule ligne suffirait pour sauvegarder une personne, et pour la charger aussi :) . Je vous laisse en juger vous même :

Avec fprintf :

fprintf( fichier , "%d\n" , personne.age); fprintf( fichier , "%s\n" , personne.nom); fprintf( fichier , "%s\n" , personne.prenom); fprintf( fichier , "%s\n" , personne.adresse); fprintf( fichier , "%d\n" , personne.nombreFreres);

Avec fwrite :

fwrite( &personne , sizeof(personne) , 1 , fichier);

Nous verrons tous ça plus en détail plus loin :) .

Utilisation de fwrite

Comment s'utilise fwrite ?

Je rappelle que le prototype de cette fonction est :

size_t fwrite (const void *ptr, size_t size, size_t nmemb, FILE *stream);
  • ptr pointeur sur le premier octet de la liste d'objets à inscrire.

  • size L'espace mémoire pris par un membre de la liste d'objets à inscrire.

  • nmemb Le nombre de membres ayant la taille size dans la liste d'objets à inscrire.

  • stream Pointeur sur le flux (pointeur sur FILE dans notre cas).

  • Valeur retournée La fonction fwrite retourne le nombre d'éléments qu'elle a réussi à inscrire correctement dans le flux pointé par stream.

Ecriture d'une variable dans un fichier

Admettons que je veuille sauvegarder ma variable 'var' dans mon fichier, j'utiliserai donc fwrite ainsi :

int var = 15; fwrite( &var , sizeof(int) , 1 , fichier);

D'où vient le 'fichier' ?

Et bah le 'fichier' c'est le fichier dans lequel je souhaite sauvegarder ma variable, que je dois avoir ouverte préalablement à l'aide de fopen comme ceci :

FILE * fichier; fichier = fopen("monfichier.bin" , "wb");

Il faut noter les choses suivantes avec la légende "très important" :) :

  • L'extension du fichier n'a pas d'importance, mais ici j'ai choisi le .bin, pour éviter le .txt. Car, contrairement au mode formaté qu'on a vu précédemment, un fichier écrit en mode binaire ne doit pas être ouvert ou édité avec un éditeur de texte classique (Bloc-notes par exemple), mais par un éditeur de fichiers binaires.
    De toute façon, le contenu de notre fichier ne sera pas exploitable généralement :p

  • "wb" : le 'b' ici indique à fopen qu'on souhaite ouvrir le fichier en mode binaire (donc non formaté), ce même 'b' peut être combiné avec tous les autres modes de la fonction fopen (a,r,w,...).
    Dans le cas de r+,a+ ou w+, le 'b' doit être entre la lettre et le signe '+' comme ceci : "rb+".

  • Et le plus important, toujours tester le retour de fopen >_

Maintenant que nous savons ouvrir un fichier en mode binaire, analysons la ligne : fwrite( &var , sizeof(int) , 1 , fichier);

1- J'appelle ma fonction fwrite.
2- Je lui donne un pointeur sur l'espace mémoire que je cherche à sauvegarder.
3- Je lui dis que cet espace fait (sizeof(int) ) 4 octets dans notre cas.
4- Je lui dis qu'il n'y a qu'un seul élément.
5- Et je lui dis que c'est dans 'fichier' que je voudrais sauvegarder tout ça :) .

Ecriture d'un tableau alloué statiquement dans un fichier

Si j'ai maintenant un tableau de int comme ceci :

int tab[10];

Et que je veuille le sauvegarder dans un fichier alors c'est simple :) , il suffit de faire ceci :

fwrite( tab , sizeof(int) , 10 , fichier);

Et oui pas besoin de faire une boucle pour inscrire mon tableau case par case ;) .
Car on a demandé à la fonction fwrite d'inscrire l'espace mémoire pointé par 'tab', et dont la portée est 10 x 4 octets. Ce qui correspond aux 10 éléments de mon tableau.

Je vais vous conseiller une autre façon de le faire, que si vous décidez de changer la taille ou le type de votre tableau, cela ne vous obligera pas à changer l'appel à la fonction fwrite. L'écriture est la suivante :

fwrite( tab , sizeof(tab[0]) , sizeof(tab)/sizeof(tab[0]) , fichier);
  • sizeof (tab[0]) nous indiquera la taille de chaque élément de notre tableau (4 octets).

  • sizeof (tab) nous indiquera la taille totale allouée à notre tableau (40 octets), que si on divise par la taille de chaque élément, ceci nous donne le nombre d'éléments que contient notre tableau (10 éléments).

Ceci indépendamment du type de notre tableau et de sa taille :)

Cette méthode est valable aussi pour des tableaux à plusieurs dimensions et dont la déclaration est faite statiquement (et non par allocation dynamique)

Ainsi une utilisation comme ceci est correcte :

int tab[10][10]; fwrite( tab , sizeof(tab) , 1 , fichier);

Ce cas est seulement pour une déclaration dite "statique" de notre tableau, pour un cas d'allocation dynamique, ceci n'est plus valable.

Ecriture d'un tableau alloué dynamiquement dans un fichier

Si je dispose d'un tableau que j'ai alloué dynamiquement par malloc comme ceci :

int * ptab; ptab = malloc(10 * sizeof(int)); //Ne pas oublier de tester le retour de malloc !

la sauvegarde dans notre fichier s'effectuera de la même façon qu'un tableau statique :

fwrite( ptab , sizeof(int) , 10 , fichier);

Ou indépendemment du type ainsi :

fwrite( ptab , sizeof (* ptab) , 10 , fichier);

Ceci n'est pas vrai dans le cas de tableaux à plusieurs dimensions (alloués dynamiquement), il faudrait écrire chaque dimensions comme présenté ci-dessus.

Ecriture d'un pointeur dans un fichier

Ce cas est très identique à celui d'un tableau alloué dynamiquement.

Si on a un pointeur 'ptr' ayant une taille allouée de 'size' octets, alors fwrite s'utilise ainsi :

fwrite ( ptr , size , 1 , fichier);

ainsi, tout le bloc mémoire alloué pour notre pointeur sera considéré comme un seul élément uni (d'où le 1 au 3ième argument).

On peu également considérer que la mémoire comporte 'size' éléments de taille 1 octet, auquel cas l'utilisation de fwrite devient :

fwrite ( ptr , 1 , size , fichier);

Il s'agit de deux notions différentes, et qui aboutiront à deux façons parfois différentes de construire notre fichier.
Alors dans la lecture avec fread, on fera attention à respecter ce détail.

Ecriture d'une structure dans un fichier

L'écriture d'une structure est très similaire aux cas présentés ci-dessus, car pour fwrite, encore une fois, la structure ne sera qu'une suite d'octets. Cependant, il y a quelques petites notions à comprendre :) . D'ailleurs c'est pourquoi je fais ce tutoriel.

Si nous avons une structure comme ceci :

typedef struct { int age; char nom[30]; char prenom[30]; }Personne;

Alors il n'y aucun problème à l'utilisation de l'opérateur sizeof pour savoir la taille de notre structure.

Personne personne1 = {15,{"NOM"},{"Prenom"}}; fwrite( &personne1 , sizeof(personne1) , 1 , fichier );

Maintenant si on a une structure comme ceci :

typedef struct { int age; char * nom; char * prenom; }Personne; Personne personne1 = {15,"TOTO","TATA"};

Alors si on essaie de récupérer la taille de cette dernière par un sizeof, ceci nous donnera la taille de age + la taille de 'nom' + la taille de 'prenom'.

Où est le problème ?

Le problème est que 'nom' et 'prenom' sont deux variables de type pointeur. Et leurs tailles sont les tailles d'un pointeur (généralement 4 octets) et non celles des chaines de caractères sur lesquelles ils pointent.

ainsi le résultat de sizeof(prsonne1) donnerait 12 octets (4 + 4 + 4) quelque soient les chaines sur lesquelles ils pointent.

fwrite( &personne1 , sizeof(personne1) , 1 , fichier );

Si on essaie malgré cela, d'utiliser fwrite comme indiqué ci-dessus, cela va sauvegarder les adresses des chaines pointées par 'nom' et 'prenom'. Qui seront, après la fermeture du programme, non signifiantes. Et leur utilisation aboutirait à un SEGFAULT ou ACCESS VIOLATION à coup sûr (sauf cas de chance :-° ).

Comment faire alors dans de tels cas :( ?

2 solutions sont possibles :

Solution 1 :

Inscrire séparément l'age, le nom et le prénom. Dans ce cas je vous conseille vivement d'utiliser fprintf comme vous l'avez appris :)

Solution 2 :

Procéder à une sérialisation de nos données (age, nom et prénom).

C'est quoi une sérialisations ?

Une...

Appeler le centre

Avez-vous besoin d'un coach de formation?

Il vous aidera à comparer différents cours et à trouver la solution la plus abordable.

Lecture et écriture de fichiers en mode binaire

Prix sur demande