Partage
  • Partager sur Facebook
  • Partager sur Twitter

Écrire et lire dans un fichier binaire (.dat)

Problème de lecture dans un fichier binaire

22 novembre 2020 à 0:05:15

Bonjour,

J'ai un problème concernant la lecture d'un fichier binaire. J'ai un fichier en format binaire scores.dat dans lequel se trouve les pseudos de 4 joueurs puis ensuite leurs scores. Nous avons un tableau en int*** car on y trouve les parties, les manches (une partie est le total de 4 manches), ainsi que le score de chaque joueur lors d'une manche. Par exemple tab[2][3][1] représente le score de la deuxième partie lors de la troisième manche du premier joueur.

Le problème est que je ne sais pas lire fichier binaire, ou tout du moins il me semble que je le lis de la mauvaise manière. Avec le code ci-dessous, j'arrive bien à écrire les pseudos, mais dès que l'on passe aux scores, ceux-ci ne s'affichent pas avec la commande cat de linux. De plus, je n'arrive pas non plus à lire le fichier, même si j'ignore si cela est lié à l'écriture des scores.

Le fichier traitement_fichier_score.c :

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "recuperer_pseudo_clavier.h"
#include "traitement_fichier_score.h"

void enregistrer_donnees_fichier(int*** tableauDonneesJeu, char* pseudo1, char* pseudo2, char* pseudo3, char* pseudo4)
{
	FILE *fichierScores=NULL;
	
	fichierScores=fopen("scores.dat","wb");

	fwrite(pseudo1,sizeof(char),LONGUEUR_PSEUDO,fichierScores);
	fwrite(pseudo2,sizeof(char),LONGUEUR_PSEUDO,fichierScores);
	fwrite(pseudo3,sizeof(char),LONGUEUR_PSEUDO,fichierScores);
	fwrite(pseudo4,sizeof(char),LONGUEUR_PSEUDO,fichierScores);
	
	fwrite(tableauDonneesJeu,sizeof(tableauDonneesJeu),1,fichierScores);
}

void lire_donnees_fichier(int*** tableauDonneesJeu, char* pseudo1, char* pseudo2,char* pseudo3,char* pseudo4)
{
	FILE *fichierScores=NULL;
	
	fichierScores=fopen("scores.dat","rb");
	
	fread(pseudo1,sizeof(pseudo1),1,fichierScores);
	fread(pseudo2,sizeof(pseudo2),1,fichierScores);
	fread(pseudo3,sizeof(pseudo3),1,fichierScores);
	fread(pseudo4,sizeof(pseudo4),1,fichierScores);
	
	fread(tableauDonneesJeu,sizeof(tableauDonneesJeu),1,fichierScores);
}


int main(void)
{
	int*** scoresTotaux;
	int i=0,j=0,k=0;
	char pseudo1[LONGUEUR_PSEUDO], pseudo2[LONGUEUR_PSEUDO], pseudo3[LONGUEUR_PSEUDO], pseudo4[LONGUEUR_PSEUDO];
	
	
	strcpy(pseudo1,"aaaa"); strcpy(pseudo2,"bbbb"); strcpy(pseudo3,"cccc"); strcpy(pseudo4,"dddd");	
	
	scoresTotaux=(int***)malloc(sizeof(int**)*NB_SCORES_ENREGISTRES);
	
	for(i=0;i<NB_SCORES_ENREGISTRES;i++)
	{
		scoresTotaux[i]=(int**)malloc(sizeof(int*)*(NB_MANCHES_MAX+1));
		
		for(j=0;j<NB_MANCHES_MAX+1;j++)
		{
			scoresTotaux[i][j]=(int*)malloc(sizeof(int)*NB_JOUEURS);
		}
	}
	
	
	for(i=0;i<NB_SCORES_ENREGISTRES;i++)
	{	
		for(j=0;j<NB_MANCHES_MAX+1;j++)
		{
			for(k=0;k<NB_JOUEURS;k++)
			{
				scoresTotaux[i][j][k]=i+j+k;
			}
		}
	}
	
	//~ enregistrer_donnees_fichier(scoresTotaux,pseudo1,pseudo2,pseudo3,pseudo4);
	lire_donnees_fichier(scoresTotaux, pseudo1, pseudo2, pseudo3, pseudo4);
	
	printf("pseudo1 %s pseudo2 %s pseudo3 %s pseudo4 %s\n",pseudo1,pseudo2,pseudo3,pseudo4);
	return 0;
}

Le fichier "recuperer_pseudo_clavier.h" ne sert que pour avoir la macroconstante LONGUEUR_PSEUDO qui est égale à 10.

Les nombres donnés au tableau 3D sont arbitraires, ils servent juste à tester si j'arrive à bien les copier et les lire.

Le fichier traitement_fichier_score.h :

#ifndef TRAITEMENT_FICHIER_SCORE_H
#define TRAITEMENT_FICHIER_SCORE_H

#define NB_JOUEURS 4
#define NB_MANCHES_MAX 4
#define NB_SCORES_ENREGISTRES 10

void enregistrer_donnees_fichier(int*** tableauDonneesJeu, char* pseudo1, char* pseudo2,char* pseudo3,char* pseudo4);
void lire_donnees_fichier(int*** tableauDonneesJeu, char* pseudo1, char* pseudo2,char* pseudo3,char* pseudo4);


#endif


Merci d'avance pour votre aide!

  • Partager sur Facebook
  • Partager sur Twitter
22 novembre 2020 à 1:58:10

Salut,
D'abord, n'espères pas pouvoir afficher un fichier binaire avec  cat  car cette commande ne traite que les fichiers en texte.
Ensuite,  sizeof(char(  vaut toujours 1. Cela allourdit le code inutilement de le mettre.
Pourquoi ne pas avoir fait un tableau de pseudo plutôt que 4 pseudo différents?
Ensuite, as-tu affiché la valeur de  sizeof(tableauDonneesJeu) ?
Je suis prêt à parier que ce sera 4 ou 8 dépendamment de ton processeur (32-bits ou 64-bits).
Ce que tu devras fournir à ton fwrite() et ton fread() est la longueur totale de ce que tu as réservé avec tes malloc.
Et ce n'est pas tout ... ce serait trop facile ...
Tu recopies sur ton fichier des adresses (ou pointeurs(. Qui te dit que les adresses seront les mêmes lors de la lecture?
Je suggère plutôt de faire des fprintf() de ces informations en format texte dans le fichier et de les lire de la même manière.
Assures-toi que les formats seront fixes pour éviter des problèmes. Par exemple %4d au lieu de %d (qui ne prendrait qu'une position pour un nombre inférieur à 10).
  • Partager sur Facebook
  • Partager sur Twitter

Le Tout est souvent plus grand que la somme de ses parties.

22 novembre 2020 à 10:59:32

Bonjour,

On distingue en gros 2 sortes de fichiers, les fichiers textes qui sont affichables et les binaires qui ne sont pas du texte et donc ne sont pas affichables.
Une première question a se poser est : est-ce que je veux un fichier texte ou un fichier binaire?
Ce choix aura pour conséquence des lourdeurs ou des simplicités, par exemple :

fichier texte :
- est affichable
- supporte assez facilement des structures de tailles variables (comme des textes par exemple)
- ne peut être écrit et lu que séquentiellement (du début vers la fin), impossible d'accéder directement à la i-ème donnée.
- écriture/lecture de valeur numérique plus lourde qu'un fichier binaire avec risque de perte de précision sur les flottants.

fichier binaire :
- n'est pas affichable
- bien pour des enregistrement où tout a une taille fixée. Pour les textes on les place dans une zone de taille maximale.
- peut être écrit et lu avec accès direct à la i-ème donnée (car données de tailles fixes)
- écriture/lecture des valeurs numérique sans perte de précision
- écriture/lecture des textes plus complexe
- le fichier est généralement plus petit que l'équivalent en fichier texte.
- la lecture/écriture est généralement plus rapide que le fichier texte.

 Si on ne sait pas trop et qu'on débute, le fichier texte est à préférer.

Comme l'a indiqué Pierrot tu écris dans le fichier des pointeurs, un pointeur ne correspond à rien quand il est hors de ton application, c'est un simple nombre qui indique la position relative d'objets dans la mémoire actuelle de ton programme.
As-tu compris ce qu'est un pointeur et ce qu'est un tableau? int*** xxx ne désigne pas un tableau, ça correspond à l'adresse d'un tableau de pointeurs qui pointent sur un tableau de pointeurs qui pointent sur des tableaux d'int. C'est donc un nombre! C'est vrai que l'on peut utiliser la notation xxx[a][b][c] pour accéder à l'int comme si c'était un tableau, le compilateur réinterprète le texte comme étant *(*(*(xxx+a)+b)+c), essaie de comprendre cette expression en faisant un dessin c'est plus facile.

Pour écrire tous les int, il te faut parcourir tous les éléments du 'tableau' et les sauver dans le fichier un après l'autre, en format texte ou binaire, à toi de choisir.

  • Partager sur Facebook
  • Partager sur Twitter

En recherche d'emploi.

23 novembre 2020 à 19:49:23

En fait nous nous sommes mis la contrainte d'utiliser un fichier binaire comme nous avions déjà utilisé un fichier texte. Du coup j'aimerais pouvoir réussir à manipuler un fichier binaire.

J'ai donc créé un tableau de pseudos comme conseillé, et j'arrive à lire presque tous les pseudos et entiers. Pour une raison que j'ignore, si j'essaie de lire le premier pseudo ou les scores du premier tableau, j'obtiens une erreur de segmentation. J'ai beau chercher, je ne vois pas vraiment d'où pourrait provenir l'erreur. Autrement dit, si je cherche à manipuler ou afficher tableauPseudos[0] ou scoreTotaux[0][x][x], j'obtiens une erreur de segmentation.

Ce qui est étrange, c'est que le reste fonctionne : si j'essaie d'afficher les autres pseudos ou les autres scores, je n'ai aucun problème et ce sont les bonnes valeurs/chaînes de caractères qui s'affichent.

Je mets le nouveau code, même si assez similaire, ci-dessous :

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "recuperer_pseudo_clavier.h"
#include "traitement_fichier_score.h"

void enregistrer_donnees_fichier(int*** tableauDonneesJeu, char** tableauPseudos)
{
	FILE *fichierScores=NULL;
	
	fichierScores=fopen("scores.dat","wb");

	fwrite(tableauPseudos,sizeof(tableauPseudos),1,fichierScores);
	fwrite(tableauDonneesJeu,sizeof(tableauDonneesJeu),1,fichierScores);
}

void lire_donnees_fichier(int*** tableauDonneesJeu, char** tableauPseudos)
{
	FILE *fichierScores=NULL;
	
	fichierScores=fopen("scores.dat","rb");

	fread(tableauPseudos,sizeof(tableauPseudos),1,fichierScores);
	fread(tableauDonneesJeu,sizeof(tableauDonneesJeu),1,fichierScores);
}


int main(void)
{
	int ***scoresTotaux;
	int i=0,j=0,k=0;
	char pseudo1[LONGUEUR_PSEUDO]="aaaaa", pseudo2[LONGUEUR_PSEUDO]="bbbbb", pseudo3[LONGUEUR_PSEUDO]="ccccc", pseudo4[LONGUEUR_PSEUDO]="ddddd";
	char **tableauPseudos;

	
	tableauPseudos=(char**)malloc(sizeof(char*)*NB_JOUEURS);
	
	for(i=0;i<NB_JOUEURS;i++)
	{tableauPseudos[i]=(char*)malloc(sizeof(char)*(LONGUEUR_PSEUDO));}

	strcpy(tableauPseudos[0],pseudo1); strcpy(tableauPseudos[1],pseudo2); strcpy(tableauPseudos[2],pseudo3); strcpy(tableauPseudos[3],pseudo4);
	
	
	
	
	scoresTotaux=(int***)malloc(sizeof(int**)*NB_SCORES_ENREGISTRES);
	
	for(i=0;i<NB_SCORES_ENREGISTRES;i++)
	{
		scoresTotaux[i]=(int**)malloc(sizeof(int*)*(NB_MANCHES_MAX+1));
		
		for(j=0;j<NB_MANCHES_MAX+1;j++)
		{scoresTotaux[i][j]=(int*)malloc(sizeof(int)*NB_JOUEURS);}
	}
	
	
	for(i=0;i<NB_SCORES_ENREGISTRES;i++)
	{	
		for(j=0;j<NB_MANCHES_MAX+1;j++)
		{
			for(k=0;k<NB_JOUEURS;k++)
			{
				scoresTotaux[i][j][k]=i+j+k;
				//~ printf("|%2d|",scoresTotaux[i][j][k]);
			}
			//~ printf("\n");
		}
		//~ printf("\n");
	}
	
	//~ enregistrer_donnees_fichier(scoresTotaux,tableauPseudos);
	lire_donnees_fichier(scoresTotaux,tableauPseudos);
	
	
	printf("%s %s %s %s\n",tableauPseudos[0],tableauPseudos[1],tableauPseudos[2],tableauPseudos[3]);
	printf("score %d\n",scoresTotaux[0][2][0]);
	return 0;
}

Ce sont les 2 dernières lignes qui provoquent une erreur de segmentation (vu qu'elles demandent les premières données des 2 tableaux).

Merci à vous!

-
Edité par Shiruba 23 novembre 2020 à 19:51:56

  • Partager sur Facebook
  • Partager sur Twitter
23 novembre 2020 à 23:38:28

Hello,

C'est ta manière d'écrire dans le fichier qui est foireuse.

Je ne vais écrire qu'au sujet de tableauPseudos, tu feras le lien pour le de tabeau score.

D'abord, sizeof(tableauPseudos) ne va pas donner la taille allouée par les malloc(), mais bien la taille de cette variable, soit celle d'un pointeur.

Ensuite, rien ne garanti que les différents malloc() se suivent en mémoire.

Donc, ce qui fonctionne, c'est

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define NB_JOUEURS				4
#define LONGUEUR_PSEUDO			10
#define NB_SCORES_ENREGISTRES	3
#define NB_MANCHES_MAX			2
 
void enregistrer_donnees_fichier(char** tableauPseudos,int ***scores) {
	FILE *fichierScores;
	
	fichierScores=fopen("scores.dat","wb");
	for(int i=0;i<NB_JOUEURS;i++)
		fwrite(tableauPseudos[i],LONGUEUR_PSEUDO,1,fichierScores);
	
	for(int i=0;i<NB_SCORES_ENREGISTRES;i++)
		for(int j=0;j<NB_MANCHES_MAX+1;j++)
			fwrite(scores[i][j],NB_JOUEURS*sizeof(int),1,fichierScores);

	fclose(fichierScores);
}


void lire_donnees_fichier(char** tableauPseudos,int ***scores) {
	FILE *fichierScores;
	
	fichierScores=fopen("scores.dat","rb");
	for(int i=0;i<NB_JOUEURS;i++)
		fread(tableauPseudos[i],LONGUEUR_PSEUDO,1,fichierScores);

	for(int i=0;i<NB_SCORES_ENREGISTRES;i++)
		for(int j=0;j<NB_MANCHES_MAX+1;j++)
			fread(scores[i][j],NB_JOUEURS*sizeof(int),1,fichierScores);

	fclose(fichierScores);
}


void displayPseudos(char **tableauPseudos) {
    for(int i=0;i<NB_JOUEURS;i++)
        printf("%d %s\n",i,tableauPseudos[i]);
	puts("");
}	


void displayScores(int ***scores) {
	for(int i=0;i<NB_SCORES_ENREGISTRES;i++) {
		printf("scores_en: %d\n",i);
		for(int j=0;j<NB_MANCHES_MAX+1;j++) {
			printf("\tmanche %d\n\t\t",j);
			for(int k=0;k<NB_JOUEURS;k++)
				printf("%d ",scores[i][j][k]);
			puts("");
		}
	}
}


int main(void) {
    char pseudo[NB_JOUEURS][LONGUEUR_PSEUDO]={"aaaaa","bbbbb","ccccc","ddddd"};
     
    char **tableauPseudos=malloc(sizeof(char *)*NB_JOUEURS);
    for(int i=0;i<NB_JOUEURS;i++) {
        tableauPseudos[i]=malloc(LONGUEUR_PSEUDO);
        strcpy(tableauPseudos[i],pseudo[i]);
    }
	
	int ***scores=malloc(sizeof(int **)*NB_SCORES_ENREGISTRES);
	for(int i=0;i<NB_SCORES_ENREGISTRES;i++) {
		scores[i]=malloc(sizeof(int *)*(NB_MANCHES_MAX+1));
		for(int j=0;j<NB_MANCHES_MAX+1;j++) {
			scores[i][j]=malloc(sizeof(int)*NB_JOUEURS);
			for(int k=0;k<NB_JOUEURS;k++)
				scores[i][j][k]=i+j+k;
		}
	}
 
	displayPseudos(tableauPseudos);
	displayScores(scores);
    enregistrer_donnees_fichier(tableauPseudos,scores);

    for(int i=0;i<NB_JOUEURS;i++)
        *(tableauPseudos[i])=0;
	displayPseudos(tableauPseudos);

	for(int i=0;i<NB_SCORES_ENREGISTRES;i++)
		for(int j=0;j<NB_MANCHES_MAX+1;j++)
			for(int k=0;k<NB_JOUEURS;k++)
				scores[i][j][k]=-1;
	displayScores(scores);

    lire_donnees_fichier(tableauPseudos,scores);
	displayPseudos(tableauPseudos);
	displayScores(scores);
     
    // faire les free()
 
    return 0;
}

-
Edité par edgarjacobs 24 novembre 2020 à 1:04:47

  • Partager sur Facebook
  • Partager sur Twitter

On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent

24 novembre 2020 à 1:14:41

@edgarjacobs:
Merci de l'avoir écrit pour moi. Je n'avais pas le goût de le faire ...
On n'est pas en Python où le pointeur nous amènerait vers toutes les informations, y compris la longueur du tableau.
  • Partager sur Facebook
  • Partager sur Twitter

Le Tout est souvent plus grand que la somme de ses parties.

25 novembre 2020 à 16:18:58

@PierrotLeFou

De rien :-)

Je n'avais pas envie de trop me fouler non plus: il y a un mélange français / anglais, mais pour une fois, zut.

De plus, comme tout est parametré via de #define, à quoi bon s'amuser à faire des malloc() ? (mais bon, on peut imaginer que les define, c'est juste pour tester).

-
Edité par edgarjacobs 25 novembre 2020 à 20:49:59

  • Partager sur Facebook
  • Partager sur Twitter

On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent