Menu

Lecture et écriture dans un fichier .txt [Résolu]

Messages postés
32
Date d'inscription
samedi 23 février 2019
Statut
Membre
Dernière intervention
11 mai 2019
-
Bonjour,
j'ai un projet à faire pour mes études et mon groupe et moi, on est dessus depuis un ptit temps maintenant, et là je coince depuis un moment sur quelques fonctions concernant globalement ce qui est de l'écriture et de la lecture dans un fichier. Je sais qu'il y a déjà eu des topics et tout à ce sujet et j'ai beau essayer de suivre ce qui en ressort, ça ne m'avance pas j'ai toujours le même problème et je ne sais pas comment le résoudre...

Voici en gros ce que mes fonctions doivent faire :
#ifndef THEMES_H_INCLUDED
#define THEMES_H_INCLUDED
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define FICHIER_THEMES ".\\fichiers\\themes.txt"
#define NB_THEMES_MAX 100
#define LONG_ENREG_THEME 75

struct Theme {
    int identifiant;
    char libelle[50];
};

 // crée ou vide le fichier des themes
 void initialiserFichierThemes() ;

 // renvoie le nombre de themes stockés.
 int nombreThemes();

 // compare les 2 thèmes reçus en paramètre.
 // si ils ont le même identifiant et le même libellé, la fonction renvoie 1.
 // si ce n'est pas le cas, elle renvoie 0.
 int themesIdentiques(struct Theme theme1, struct Theme theme2);

 // compare les 2 thèmes reçus en paramètre. La comparaison se fait sur les libellés.
 // si le libellé du thème 1 se trouve avant le libellé du thème 2 dans l'ordre lexicographique, elle renvoie un nombre <0.
 // si le libellé du thème 2 se trouve avant le libellé du thème 1 dans l'ordre lexicographique, elle renvoie un nombre <0.
 // si les libellés sont identiques, elle renvoie 0.
 // Utilisez la fonction strcmp()
 int comparerThemes(struct Theme theme1, struct Theme theme2);

 // ajoute un theme.
 // cette fonction doit affecter un identifiant au thème reçu en paramètre.
 // elle renvoie l'identifiant affecté au thème.
 // si erreur, elle renvoie 0.
 int ajouterTheme(struct Theme theme);


 // garnit le tableau reçu en paramètre avec les thèmes stockés.
 // renvoie le nombre de thèmes contenus dans le tableau
 int listerThemes(struct Theme themes[]);

 // recherche si un thème existe. Recherche sur base de l'identifiant.
 // renvoie 1 si le thème est stocké.
 // renvoie 0, si pas présent.
 int themeExiste(int identifiant);

 // recherche le libellé du thème dont on reçoit l'identifiant en paramètre
 // si le thème identifié est présent, on recopie son libellé dans le paramètre libelle. On renvoie 1.
 // si le thème n'est pas présent, on affecte une chaine vide au paramètre libelle. On renvoie 0.
 int rechercherLibelleTheme(int identifiant, char libelle[]);

 // modifie le libellé du thème identifié par l'identifiant reçu en paramètre.
 // si le thème est présent, son libellé est modifié. La valeur 1 est renvoyée.
 // si aucun thème ne correspond à cet identifiant, la fonction renvoie 0.
 int modifierTheme(int identifiant, char nouveauLibelle[]);

 // Supprime un thème. L'identifiant du thème à supprimer est passé en paramètre.
// Suppression "logique". Les données ne sont supprimées "physiquement").
// si l'identifiant reçu en paramètre correspond à un thème stocké, celui-ci est supprimé et elle renvoie 1.
// si l'identifiant reçu en paramètre ne correspond à aucun thème stocké, elle renvoie 0.
int supprimerTheme(int identifiant);

// supprime pysiquement le contenu du fichier des thèmes.
// renvoie le nombre de thèmes qui ont été supprimés.
int supprimerTousLesThemes();

 // garnit le tableau reçu en paramètre avec les thèmes triés de façon ascendante sur leur libellé.
 // renvoie le nombre de thèmes contenus dans le tableau
 int listerThemesTries(struct Theme themes[]);

#endif // THEMES_H_INCLUDED


Et voici ce que moi j'ai codé pour le moment :
void initialiserFichierThemes()
{
    /* Declaration */
    FILE *fout=NULL;

    /* Ouverture du fichier */
    fout=(fopen(FICHIER_THEMES,"wt"));

    /* Fermeture du fichier */
    fclose(fout);
}

int nombreThemes()
{
    /* Declaration */
    int nbThemes=0;

    struct Theme theme;

    FILE *fin=NULL;

    /* Ouverture du fichier */
    fin=(fopen(FICHIER_THEMES,"rt"));

    /* Traitement */
    if ((fscanf(fin,"%d %s",&theme.identifiant,&theme.libelle[0]))==2)
    {
        nbThemes++;
        while ((fscanf(fin,"%d %s",&theme.identifiant,&theme.libelle[0]))==2)
        {
            nbThemes++;
        }
    }

    /* Fermeture du fichier */
    fclose(fin);

    return(nbThemes);
}

int themesIdentiques(struct Theme theme1, struct Theme theme2)
{
    /* Traitement */
    if ((strcmp(theme1.libelle,theme2.libelle)==0) && (theme1.identifiant==theme2.identifiant)) return(1); // Les themes sont identiques

    return(0); // Les themes ne sont pas identitques
}
int comparerThemes(struct Theme theme1, struct Theme theme2)
{
    /* Declaration */
    int car;

    /* Traitement */
    car=strncmp(theme1.libelle, theme2.libelle, 1); // sauvegarde le resultat de strncmp

    if(car < 0) return (-1); // Le libelle du theme 1 se trouve avant le libelle du theme 2 dans l'ordre lexicographique
    else if(car > 0) return (-2); // Le libelle du theme 2 se trouve avant le libelle du theme 1 dans l'ordre lexicographique
    else return (0); // Les libelles sont identiques
}

int ajouterTheme(struct Theme theme)
{
    int erreur=0;
    int i=1;
    char ligne[LONG_ENREG_THEME];
    struct Theme temp;

    FILE *fout=NULL;


    if((fout=fopen(FICHIER_THEMES,"at+")))
    {
        fseek(fout,0,SEEK_END);
        if((ftell(fout))!=0)
        {
            fseek(fout,0,SEEK_SET);
            while(((fgets(ligne,LONG_ENREG_THEME,fout))!=NULL) && (erreur==0))
            {
                if((sscanf(ligne,"%d %s",&temp.identifiant,temp.libelle))==2)
                {
                    i++;
                }
                else erreur=1;
            }
            if((fprintf(fout,"%d %s\n",i,theme.libelle))>0) return(i);
            else erreur=2;
        }
        else
        {
            fseek(fout,0,SEEK_SET);
            if((fprintf(fout,"%d %s\n",i,theme.libelle))>0) return(i);
            else erreur=2;
        }

    } else erreur=1;

    switch(erreur){
    case 1: fprintf(stderr, "\n\n\n\n\n\t\t\t\tErreur lors de l'ouverture du fichier themes.txt\n\n\n\n\n"); break;
    case 2: fprintf(stderr, "\n\n\n\n\n\t\t\t\tErreur lors de l'ecriture dans le fichier themes.txt\n\n\n\n\n"); break;
    case 3: fprintf(stderr, "\n\n\n\n\n\t\t\t\tErreur lors de la lecture dans le fichier themes.txt\n\n\n\n\n"); break;
    //case 4: fprintf(stderr, "\n\n\n\n\n\t\t\t\tErreur lors du positionnemment dans le fichier themes.txt\n\n\n\n\n"); break;
    }

    return(0);
}

int listerThemes(struct Theme themes[])
{
    int tailleFichier;
    int nbThemeTab=0;
    int erreur=0;

    FILE* fin=NULL;

    if ((fin=fopen(FICHIER_THEMES,"rt+")))
    {

        fseek(fin,0,SEEK_END);
        tailleFichier=ftell(fin);
        fseek(fin,0,SEEK_SET);

        nbThemeTab=tailleFichier/LONG_ENREG_THEME;

    } else erreur=1;

    switch(erreur)
    {
    case 1: fprintf(stderr, "\n\n\n\n\n\t\t\t\tErreur lors de l'ouverture du fichier themes.txt\n\n\n\n\n"); break;
    //case 2: fprintf(stderr, "\n\n\n\n\n\t\t\t\tErreur lors de l'écriture dans le fichier themes.txt\n\n\n\n\n"); break;
    //case 3: fprintf(stderr, "\n\n\n\n\n\t\t\t\tErreur lors de la lecture dans le fichier themes.txt\n\n\n\n\n"); break;
    //case 4: fprintf(stderr, "\n\n\n\n\n\t\t\t\tErreur lors du positionnemment dans le fichier themes.txt\n\n\n\n\n"); break;
    }

    return(nbThemeTab);
}

int themeExiste(int identifiant)
{
    /* Declaration */
    int erreur=0; // variable pour stocker les resultats des tests en cas d'erreur

    FILE *fin=NULL; // Pointeur fout de type FILE

    struct Theme theme;

    /* Ouverture du fichier */
    if ((fin=fopen(FICHIER_THEMES,"rt"))); // Ouverture du fichier en mode ecriture avec un test pour verifier que le fichier s'ouvre correctement
    else erreur=1; // S'il ne s'ouvre pas


    /* Traitement */
    if(fscanf(fin,"%d %s",&theme.identifiant,&theme.libelle[0]))
    {
        while ((!feof(fin)) && (erreur!=3))
        {
            if (identifiant==theme.identifiant)
            {
                return(1);
            }
            fscanf(fin,"%d %s",&theme.identifiant,&theme.libelle[0]);
        }
    }

    /* Fermeture du fichier */
    switch(erreur)
    {
    case 1: fprintf(stderr, "\n\n\n\n\n\t\t\t\tErreur lors de l'ouverture du fichier themes.txt\n\n\n\n\n"); break;
    //case 2: fprintf(stderr, "\n\n\n\n\n\t\t\t\tErreur lors de l'écriture dans le fichier themes.txt\n\n\n\n\n"); break;
    case 3: fprintf(stderr, "\n\n\n\n\n\t\t\t\tErreur lors de la lecture dans le fichier themes.txt\n\n\n\n\n"); break;
    //case 4: fprintf(stderr, "\n\n\n\n\n\t\t\t\tErreur lors du positionnemment dans le fichier themes.txt\n\n\n\n\n"); break;
    }

    return(0);
}

int rechercherLibelleTheme(int identifiant, char libelle[])
{
    return -1;
}

int modifierTheme(int identifiant, char nouveauLibelle[])
{
    return -1;
}

int supprimerTheme(int identifiant)
{
    int erreur=0;
    char ligne[LONG_ENREG_THEME];

    FILE *fout=NULL;
    struct Theme temp;

    fout=(fopen(FICHIER_THEMES,"r+"));

    while(((fgets(ligne,LONG_ENREG_THEME,fout))!=NULL) && (erreur==0))
    {
        if((sscanf(ligne,"%d %s",&temp.identifiant,temp.libelle))==2)
        {
            if(temp.identifiant==identifiant)
            {
                strcpy(temp.libelle,"*-*");
                fprintf(fout,"%d %s",temp.identifiant,temp.libelle);
                return(1);
            }
        }
        else erreur=1;
    }

    /* Fermeture du fichier */
    switch(erreur)
    {
    case 1: fprintf(stderr, "\n\n\n\n\n\t\t\t\tErreur lors de l'ouverture du fichier themes.txt\n\n\n\n\n"); break;
    case 2: fprintf(stderr, "\n\n\n\n\n\t\t\t\tErreur lors de l'écriture dans le fichier themes.txt\n\n\n\n\n"); break;
    case 3: fprintf(stderr, "\n\n\n\n\n\t\t\t\tErreur lors de la lecture dans le fichier themes.txt\n\n\n\n\n"); break;
    //case 4: fprintf(stderr, "\n\n\n\n\n\t\t\t\tErreur lors du positionnemment dans le fichier themes.txt\n\n\n\n\n"); break;
    }

    return(0);
}

int supprimerTousLesThemes()
{

   return -1;
}

int listerThemesTries(struct Theme themes[])
{
    return -1;
}


Et voici ce qui en résultent dans mon fichier :


Je tiens aussi à préciser, que je sais qu'à certains endroits j'ai commencé à traiter les erreurs mais que ce n'est pas fini :)
Voilà, je remercie d'avance tous ceux qui prendront le temps de m'aider ^^


Configuration: Windows / Chrome 73.0.3683.103
Afficher la suite 

Votre réponse

1 réponse

Meilleure réponse
Messages postés
5106
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
22 mai 2019
771
1
Merci
Bonjour Natsuko410,

j'ai toujours le même problème

Lequel ?

Sinon, quelques réflexions en vrac :

1.

// compare les 2 thèmes reçus en paramètre. La comparaison se fait sur les libellés.
 // si le libellé du thème 1 se trouve avant le libellé du thème 2 dans l'ordre lexicographique, elle renvoie un nombre <0.
 // si le libellé du thème 2 se trouve avant le libellé du thème 1 dans l'ordre lexicographique, elle renvoie un nombre <0.
 // si les libellés sont identiques, elle renvoie 0.
 // Utilisez la fonction strcmp()
 int comparerThemes(struct Theme theme1, struct Theme theme2);


je pense qu'il y a une erreur dans le descriptif et qu'on devrait lire "si le libellé du thème 2 se trouve avant le libellé du thème 1 dans l'ordre lexicographique, elle renvoie un nombre >0."

Par rapport à ton code de comparerThemes(), tu n'utilises pas strcmp() alors qu'on te demande de le faire.

Quand je compare une chaîne "themeA" et "themeB", il me semble que "themeA" est avant "themeB" dans l'ordre lexicographique, et pas que les chaînes sont identiques.

2.

Tes boucles de lecture du contenu des fichiers sont inutilement compliquées.

Par exemple, ceci suffit pour compter les thèmes, avec, en plus un contrôle du succès de l'ouverture et une fermeture du fichier s'il a été ouvert :

    fin = fopen(FICHIER_THEMES,"r");

    /* Traitement */
    if (fin) {
        while (fscanf(fin,"%d %s",&theme.identifiant,theme.libelle) == 2)
            nbThemes++;
        fclose(fin);
    }


Quand tu ouvres un fichier en mode d'ajout avec fopen() ("a" pour append, pas "at+"), tu n'as pas à te positionner dans le fichier pour écrire à la fin. Les opérations d'écriture se feront directement à la fin.

Je ne vois nulle part dans le code de ajouterTheme() que tu retournes l'identifiant du thème ajouté.

Je ne pense pas qu'il faille déterminer l'identifiant par rapport au nombre d'éléments... mais on a déjà eu cette discussion

Pour supprimer un thème du fichier, à mon sens, tu dois :
- ouvrir le fichier en lecture contenant les thèmes (themes.txt)
- ouvrir en écriture un fichier temporaire (temp.txt)
- lire dans le fichier themes.txt chaque ligne et l'écrire dans temp.txt sauf si la ligne contient ce que tu dois supprimer
- fermer themes.txt et temp.txt avec fclose()
- effacer themes.txt et renommer temp.txt en themes.txt

Dal

Dire « Merci » 1

Heureux de vous avoir aidé ! Vous nous appréciez ? Donnez votre avis sur nous ! Evaluez CommentCaMarche

CCM 39175 internautes nous ont dit merci ce mois-ci

Natsuko410
Messages postés
32
Date d'inscription
samedi 23 février 2019
Statut
Membre
Dernière intervention
11 mai 2019
> [Dal]
Messages postés
5106
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
22 mai 2019
-
En fait, j'avais pensé pour supprimer un thème de juste modifier le libellé sans toucher à l'identifiant, de cette manière je dois juste faire un test pour savoir si le libellé est égale à "DELETED"

En gros cela ferais ça :
[Dal]
Messages postés
5106
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
22 mai 2019
771 -
en tenant pour vrai le fait que toutes tes lignes, y compris la dernière, sont terminées par un '\n'

Cela sera vrai si les lignes sont toutes créées avec ton programme, car tu les termines avec un
'\n'
dans ton code. En fait, dans ce cas tu auras :

1 cinema
2 musique
3 sport


chaque ligne est terminée par
'\n'
, y compris
"3 sport"
, et, techniquement, tu as en réalité une ligne vide en 4ème position.

Par contre, si le fichier est créé à la main, le décompte ne sera pas bon si, à la dernière ligne, tu ne tapes pas Entrée, pour aller à la ligne. Tu auras :
1 cinema
2 musique
3 sport

La ligne
"3 sport"
ne serait pas, ici, terminée par un retour à la ligne.

Il faut alors faire autrement pour compter correctement les lignes, par exemple : prendre en compte le fait que si la ligne n'est pas vide, alors elle compte comme une ligne même si elle n'est pas terminée par un retour à la ligne.
[Dal]
Messages postés
5106
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
22 mai 2019
771 -
une autre stratégie est de faire comme tu fais en faisant :
if (fscanf(fin,"%d %s",&temp.identifiant,temp.libelle))==2)
mais en ajoutant une condition le compteur soit incrémenté et que la boucle continue si la ligne contient "DELETED".

Cela permet aussi de valider le contenu du fichier. Si les deux tests échouent et que l'on n'est pas à la fin du fichier, ton programme pourrait se plaindre que la base des thèmes est corrompue et s'arrêter.
[Dal]
Messages postés
5106
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
22 mai 2019
771 -
En fait, j'avais pensé pour supprimer un thème de juste modifier le libellé sans toucher à l'identifiant, de cette manière je dois juste faire un test pour savoir si le libellé est égale à "DELETED"

Super !
Natsuko410
Messages postés
32
Date d'inscription
samedi 23 février 2019
Statut
Membre
Dernière intervention
11 mai 2019
-
Un grand merci de ton aide, je suis arrivé à tout faire, peut-être pas de la meilleure des manières mais ça tourne ^^
Commenter la réponse de [Dal]