Historique des modifications - Message

Message #8730

Sujet: lire et ecrire un fichier de sauvegarde très simplement


Type Date Auteur Contenu
Dernière modification 11-09-2010 22:44:47 nabouill
[intro] Récupérer une information enregistré dans un fichier où d'enregistrer une information dans un fichier.
Il écrit les informations désirées de façon a rendre sa lecture/modification manuel particulièrement facile.
La manipulation de fichier pour un système de sauvegarde par exemple peut s'avérer parfois pénible. Bien souvent il ressemble plutôt à çà:


le truc un peut barbant, il faut etre super organiser pour bien lire les données dans l'ordre, et bien les réécrire. Puis quand on veut y faire une modif manuellement, on ne sais plus vraiment à quoi ça correspond tout çà hmm

FINI l'ennuie, voici un petit bout de code qui va bien changer tout çà, maintenant on lit/enregistre ce qu'on veut, quand on veut, dans n'importe quel ordre smile grâce à 2 fonctions seulement (en passant j'en profite pour remercier Nico qui m'a mis sur la piste des template).

ancres->set(LE CODE, TEST DE LECTURE, TEST D'ECRITURE, POUR FINIR, PETITE ASTUCE); [/intro]






ancres->create(LE CODE);
voici tout le code à mettre dans un fichier .h:

Code c++ :


#ifndef NA_FINDORWRITEINFILE_H
#define NA_FINDORWRITEINFILE_H

/*
NA_FindOrWriteInFile
créer le 11/09/2010

Role: recupérer une information enregistré dans un fichier
      où enregistrer une information dans un fichier.
      Il ecrit les informations desirées de façon a rendre sa lecture/modification
      manuel particulerment facile.
      L'extention du fichier peut être de n'importe quelle type (txt, ini, dat... et même aucune)

exemple du fichier:

prenom= Nabouill
age= 27
pays= France
*/

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

/// ***********************************************************************************
///                       GET INFO IN FILE
/// ***********************************************************************************

template<typename T>
bool getInfoInFile(const char path[], std::string info, T & Data )
{
    info += "=";//rajoute le "=" a l'info pour la recherche dans le fichier
    int longueurInfo = info.size();
    char ligne[256];//pour lire la ligne
    std::string sparam; //pour remettre le parametre lu dans un string

    FILE* fichier = fopen(path, "r");//ouverute du fichier
    rewind(fichier);//on revient au debut du fichier pour etre sûr

    bool continuer = true;
    while(continuer)
    {
        if(fgets(ligne, 255, fichier) != NULL)
        {   //on recherche dans cette ligne l'info et on verifie si on la trouve
            if(strstr(ligne, info.c_str()))
            {   //si on la trouve
                int longueurLigne = strlen(ligne);
                //on recule dans le fichier jusqu'au =
                fseek(fichier, (longueurInfo - longueurLigne -1), SEEK_CUR);
                //on recuperer le parametre de l'info dans le fichier
                char paramTemp[256];
                fscanf(fichier, "%s", paramTemp);
                //on remet ça dans un string
                sparam = paramTemp;
                continuer = false;
            }
        }
        else// sinon c'est qu'on n'a jamais trouvé l'info
        {   //on ecrit donc une valeur par default
            sparam = "0";
            continuer = false;
        }

    }
    //on ferme le fichier
    fclose(fichier);

    //convertion du string en parametre a renvoyer
    std::istringstream param( sparam );
    return param >> Data != 0;
}

/// ***********************************************************************************
///                       SAVE INFO IN FILE
/// ***********************************************************************************


template<typename T>
void saveInfoInFile(const char path[], std::string info, T & Data )
{
    //convertion du Parametre du type envoyer en string
    std::ostringstream oss;
    oss << Data;
    std::string sparam = oss.str();//contient le parametre


    info += "=";//rajoute le "=" a l'info pour la recherche dans le fichier

    FILE* fichier = fopen(path, "r");//ouverute du fichier

    //si on arrive pas, on suggere qu'il n'existe pas, donc on le crée
    //et on ecrit l'info + le parametre a sauvegarder dedans
    if(fichier == NULL)
    {
        fichier = fopen(path, "a");//dans on le cree
        rewind(fichier);//on revient au debut du fichier pour etre sûr
        fprintf(fichier, "%s %s\
",info.c_str(), sparam.c_str());//on ecrit dans le fichier
        fclose(fichier);//on ferme le fichier
    }
    else// on a reussi a ouvrir le fichier
    {
        //on creer un fichier temporaire
        std::string pathTemp = path;
        pathTemp+= "Temp";
        FILE *fichierTemp = fopen(pathTemp.c_str(), "w+");

        char ligne[256];
        bool infoExistait = false;
        bool continuer = true;
        while(continuer)
        {
            if(fgets(ligne, 255, fichier) != NULL)
            {   //on recherche dans cette ligne l'info
                if(strstr(ligne, info.c_str()))//si on trouve
                {   infoExistait = true;
                    //on ecrit son nouveau parametre dans le fichier temp
                    fprintf(fichierTemp, "%s %s\
",info.c_str(), sparam.c_str());
                }
                else//si on ne la trouve pas
                {
                    //on ecrit dans le fichier temp ce qu'on a trouver dans le fichier original
                    fprintf(fichierTemp, "%s",ligne);
                }
            }
            else// si on a fini de lire le fichier
            {
                if(!infoExistait)//si l'info n'hexistait pas, on la rajoute a la fin du fichier
                {   fprintf(fichierTemp, "\
%s %s",info.c_str(), sparam.c_str());
                }
                continuer = false;
            }
        }
        //arrivé ici, le fichier temporaire est complet

        fclose(fichier); //fermeture du fichier original
        remove(path); //suppression du fichier original
        rewind(fichierTemp); //revient au debut du fichier temp
        fichier = fopen(path, "w+"); //recreation du fichier original

        continuer = true;
        while(continuer)
        {   //recopie integral du fichier temp dans le nouveau original
            if(fgets(ligne, 255, fichierTemp) != NULL)
            {   fprintf(fichier, "%s",ligne);
            }
            else
            {   continuer = false;
            }
        }

        //fermeture et suppression du fichier temp
        fclose(fichier);
        fclose(fichierTemp);
        remove(pathTemp.c_str());

    }

}

#endif  //NA_FINDORWRITEINFILE_H


Je ne vais pas m'attarder sur ce qu'il y a dans ce code, je l'ai déjà commenté abusivement.
On va donc passer tout de suite à ce qu'il faut retenir, ce sont juste ces 2 prototypes de fonctions enfaite:

Code c++ :

bool getInfoInFile(const char path[], std::string info, T & Data )
void saveInfoInFile(const char path[], std::string info, T & Data )

Ces fonctions prennent en paramètre:
1- le chemin du fichier que l'on veut lire ou écrire
2- l'information recherché ou a écrire dans le fichier
3- la donnée que l'on veut enregistrer
/i\\ Le dernier paramètre des ces fonction peut être de n'importe quel type (int, long, char*, string, float...) /i\\


Et grâce à çà, voilà à quoi ressemble mes fichiers de sauvegarde maintenant:



C'est quand même un peut plus lisible que ce qu'on peut trouvé parfois.



ancres->create( TEST DE LECTURE);

En gros on n'a plus qu'a demander "c'est qui ami1 ?" il me reste combien de vie ?
pour çà, on a juste a demander ce que j'appel l'information (qui se trouve avant le signe "=") et il nous renvoi ce que j'appel le Data, après le "=".
Un petit code d'exemple qui va lire le fichier de sauvegarde situer juste au dessus:

Code c++ :

#include <iostream>
#include "NA_FindOrWriteInFile.h"

using namespace std;

int main()
{
    char path[] = "sauvegarde/config.ini";

    int vieRestante;
    float posi;
    char ami_3[32];
    string ville_2;

    getInfoInFile(path, "nbvie", vieRestante);
    getInfoInFile(path, "ville2", ville_2);
    getInfoInFile(path, "position", posi);
    getInfoInFile(path, "ami3", ami_3);

    cout <<"vie Restante: " << vieRestante << endl;
    cout << "Ville 2: " << ville_2 << endl;
    cout << "posi: " << posi << endl;
    cout << "Ami 3: " << ami_3 << endl;

    return 0;
}

ce que ça nous dis:



BINGO! smile




ancres->create( TEST D'ECRITURE);

On peut aussi enregistrer ce qu'on veut dans notre fichier, si une information n'existe pas, il l'a rajoute, si elle existe, il remplace sont Data.
exemple:

Code c++ :

#include <iostream>
#include "NA_FindOrWriteInFile.h"

using namespace std;

int main()
{
    char path[] = "sauvegarde/config.ini";

    int vieRestante = 15;
    float posi = 155.789;
    char ami[32] = "Jo";
    string ville = "Villepot";

    saveInfoInFile(path, "nbvie", vieRestante);
    saveInfoInFile(path, "position", posi);
    saveInfoInFile(path, "ami1", ami);
    saveInfoInFile(path, "ville2", ville);
    //test a la mano
    saveInfoInFile("sauvegarde/config.ini", "nom_du_chien", "Dédé");

    return 0;
}

voici maintenant à quoi ressemble notre fichier de sauvegarde:


Vous pouvez comparer; c'est impec smile



ancres->create( POUR FINIR);


/i\\Info/i\\
On peut très bien rajouté des commentaires à notre fichier, cela ne pose aucun problème.
/!\\ Par contre /!\\ sur une modification manuel, il est important de bien mettre le signe "=" collé à l'information, sans espace.
Mais après le signe "=" peut importe, écrire:
ami1=pierre
ami2= paul
donne exactement le même résultat.

ancres->create( PETITE ASTUCE);

Si cette class vous plait, vous pouvez l'enregistrer ce fichier .h directement avec les fichiers des lib standard de votre compilateur (exemple pour moi avec code::block "C:\\Program Files\\CodeBlocks\\MinGW\\include"), car si on compte utiliser cette class dans plusieurs programmes, on n'a plus qu'à le mettre en entête a notre projet sans être obligé de copier le fichier dans tous nos programmes.
Création du message 08-09-2010 22:52:04 nabouill
[intro] Récupérer une information enregistré dans un fichier où d'enregistrer une information dans un fichier.
Il écrit les informations désirées de façon a rendre sa lecture/modification manuel particulièrement facile.
La manipulation de fichier pour un système de sauvegarde par exemple peut s'avérer parfois pénible. Bien souvent il ressemble plutôt à çà:


le truc un peut barbant, il faut etre super organiser pour bien lire les données dans l'ordre, et bien les réécrire. Puis quand on veut y faire une modif manuellement, on ne sais plus vraiment à quoi ça correspond tout çà hmm

FINI l'ennuie, voici un petit bout de code qui va bien changer tout çà, maintenant on lit/enregistre ce qu'on veut, quand on veut, dans n'importe quel ordre smile grâce à 2 fonctions seulement (en passant j'en profite pour remercier Nico qui m'a mis sur la piste des template).

ancres->set(LE CODE, TEST DE LECTURE, TEST D'ECRITURE, POUR FINIR, PETITE ASTUCE); [/intro]






ancres->create(LE CODE);
voici tout le code à mettre dans un fichier .h:

Code c++ :


#ifndef NA_FINDORWRITEINFILE_H
#define NA_FINDORWRITEINFILE_H

/*
NA_FindOrWriteInFile
créer le 11/09/2010

Role: recupérer une information enregistré dans un fichier
      où enregistrer une information dans un fichier.
      Il ecrit les informations desirées de façon a rendre sa lecture/modification
      manuel particulerment facile.
      L'extention du fichier peut être de n'importe quelle type (txt, ini, dat... et même aucune)

exemple du fichier:

prenom= Nabouill
age= 27
pays= France
*/

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

/// ***********************************************************************************
///                       GET INFO IN FILE
/// ***********************************************************************************

template<typename T>
bool getInfoInFile(const char path[], std::string info, T & Data )
{
    info += "=";//rajoute le "=" a l'info pour la recherche dans le fichier
    int longueurInfo = info.size();
    char ligne[256];//pour lire la ligne
    std::string sparam; //pour remettre le parametre lu dans un string

    FILE* fichier = fopen(path, "r");//ouverute du fichier
    rewind(fichier);//on revient au debut du fichier pour etre sûr

    bool continuer = true;
    while(continuer)
    {
        if(fgets(ligne, 255, fichier) != NULL)
        {   //on recherche dans cette ligne l'info et on verifie si on la trouve
            if(strstr(ligne, info.c_str()))
            {   //si on la trouve
                int longueurLigne = strlen(ligne);
                //on recule dans le fichier jusqu'au =
                fseek(fichier, (longueurInfo - longueurLigne -1), SEEK_CUR);
                //on recuperer le parametre de l'info dans le fichier
                char paramTemp[256];
                fscanf(fichier, "%s", paramTemp);
                //on remet ça dans un string
                sparam = paramTemp;
                continuer = false;
            }
        }
        else// sinon c'est qu'on n'a jamais trouvé l'info
        {   //on ecrit donc une valeur par default
            sparam = "0";
            continuer = false;
        }

    }
    //on ferme le fichier
    fclose(fichier);

    //convertion du string en parametre a renvoyer
    std::istringstream param( sparam );
    return param >> Data != 0;
}

/// ***********************************************************************************
///                       SAVE INFO IN FILE
/// ***********************************************************************************


template<typename T>
void saveInfoInFile(const char path[], std::string info, T & Data )
{
    //convertion du Parametre du type envoyer en string
    std::ostringstream oss;
    oss << Data;
    std::string sparam = oss.str();//contient le parametre


    info += "=";//rajoute le "=" a l'info pour la recherche dans le fichier

    FILE* fichier = fopen(path, "r");//ouverute du fichier

    //si on arrive pas, on suggere qu'il n'existe pas, donc on le crée
    //et on ecrit l'info + le parametre a sauvegarder dedans
    if(fichier == NULL)
    {
        fichier = fopen(path, "a");//dans on le cree
        rewind(fichier);//on revient au debut du fichier pour etre sûr
        fprintf(fichier, "%s %s\
",info.c_str(), sparam.c_str());//on ecrit dans le fichier
        fclose(fichier);//on ferme le fichier
    }
    else// on a reussi a ouvrir le fichier
    {
        //on creer un fichier temporaire
        std::string pathTemp = path;
        pathTemp+= "Temp";
        FILE *fichierTemp = fopen(pathTemp.c_str(), "w+");

        char ligne[256];
        bool infoExistait = false;
        bool continuer = true;
        while(continuer)
        {
            if(fgets(ligne, 255, fichier) != NULL)
            {   //on recherche dans cette ligne l'info
                if(strstr(ligne, info.c_str()))//si on trouve
                {   infoExistait = true;
                    //on ecrit son nouveau parametre dans le fichier temp
                    fprintf(fichierTemp, "%s %s\
",info.c_str(), sparam.c_str());
                }
                else//si on ne la trouve pas
                {
                    //on ecrit dans le fichier temp ce qu'on a trouver dans le fichier original
                    fprintf(fichierTemp, "%s",ligne);
                }
            }
            else// si on a fini de lire le fichier
            {
                if(!infoExistait)//si l'info n'hexistait pas, on la rajoute a la fin du fichier
                {   fprintf(fichierTemp, "\
%s %s",info.c_str(), sparam.c_str());
                }
                continuer = false;
            }
        }
        //arrivé ici, le fichier temporaire est complet

        fclose(fichier); //fermeture du fichier original
        remove(path); //suppression du fichier original
        rewind(fichierTemp); //revient au debut du fichier temp
        fichier = fopen(path, "w+"); //recreation du fichier original

        continuer = true;
        while(continuer)
        {   //recopie integral du fichier temp dans le nouveau original
            if(fgets(ligne, 255, fichierTemp) != NULL)
            {   fprintf(fichier, "%s",ligne);
            }
            else
            {   continuer = false;
            }
        }

        //fermeture et suppression du fichier temp
        fclose(fichier);
        fclose(fichierTemp);
        remove(pathTemp.c_str());

    }

}

#endif  //NA_FINDORWRITEINFILE_H


Je ne vais pas m'attarder sur ce qu'il y a dans ce code, je l'ai déjà commenté abusivement.
On va donc passer tout de suite à ce qu'il faut retenir, ce sont juste ces 2 prototypes de fonctions enfaite:

Code c++ :

bool getInfoInFile(const char path[], std::string info, T & Data )
void saveInfoInFile(const char path[], std::string info, T & Data )

Ces fonctions prennent en paramètre:
1- le chemin du fichier que l'on veut lire ou écrire
2- l'information recherché ou a écrire dans le fichier
3- la donnée que l'on veut enregistrer
/i\\ Le dernier paramètre des ces fonction peut être de n'importe quel type (int, long, char*, string, float...) /i\\


Et grâce à çà, voilà à quoi ressemble mes fichiers de sauvegarde maintenant:



C'est quand même un peut plus lisible que ce qu'on peut trouvé parfois.



ancres->create( TEST DE LECTURE);

En gros on n'a plus qu'a demander "c'est qui ami1 ?" il me reste combien de vie ?
pour çà, on a juste a demander ce que j'appel l'information (qui se trouve avant le signe "=") et il nous renvoi ce que j'appel le Data, après le "=".
Un petit code d'exemple qui va lire le fichier de sauvegarde situer juste au dessus:

Code c++ :

#include <iostream>
#include "NA_FindOrWriteInFile.h"

using namespace std;

int main()
{
    char path[] = "sauvegarde/config.ini";

    int vieRestante;
    float posi;
    char ami_3[32];
    string ville_2;

    getInfoInFile(path, "nbvie", vieRestante);
    getInfoInFile(path, "ville2", ville_2);
    getInfoInFile(path, "position", posi);
    getInfoInFile(path, "ami3", ami_3);

    cout <<"vie Restante: " << vieRestante << endl;
    cout << "Ville 2: " << ville_2 << endl;
    cout << "posi: " << posi << endl;
    cout << "Ami 3: " << ami_3 << endl;

    return 0;
}

ce que ça nous dis:



BINGO! smile




ancres->create( TEST D'ECRITURE);

On peut aussi enregistrer ce qu'on veut dans notre fichier, si une information n'existe pas, il l'a rajoute, si elle existe, il remplace sont Data.
exemple:

Code c++ :

#include <iostream>
#include "NA_FindOrWriteInFile.h"

using namespace std;

int main()
{
    char path[] = "sauvegarde/config.ini";

    int vieRestante = 15;
    float posi = 155.789;
    char ami[32] = "Jo";
    string ville = "Villepot";

    saveInfoInFile(path, "nbvie", vieRestante);
    saveInfoInFile(path, "position", posi);
    saveInfoInFile(path, "ami1", ami);
    saveInfoInFile(path, "ville2", ville);
    //test a la mano
    saveInfoInFile("sauvegarde/config.ini", "nom_du_chien", "Dédé");

    return 0;
}

voici maintenant à quoi ressemble notre fichier de sauvegarde:


Vous pouvez comparer; c'est impec smile



ancres->create( POUR FINIR);


/i\\Info/i\\
On peut très bien rajouté des commentaires à notre fichier, cela ne pose aucun problème.
/!\\ Par contre /!\\ sur une modification manuel, il est important de bien mettre le signe "=" collé à l'information, sans espace.
Mais après le signe "=" peut importe, écrire:
ami1=pierre
ami2= paul
donne exactement le même résultat.

ancres->create( PETITE ASTUCE);

Si cette class vous plait, vous pouvez l'enregistrer ce fichier .h directement avec les fichiers des lib standard de votre compilateur (exemple pour moi avec code::block "C:\\Program Files\\CodeBlocks\\MinGW\\include"), car si on compte utiliser cette class dans plusieurs programmes, on n'a plus qu'à le mettre en entête a notre projet sans être obligé de copier le fichier dans tous nos programmes.

Retour

Options Liens officiels Caractéristiques Statistiques Communauté
Préférences cookies
Corrections
irrlicht
irrklang
irredit
irrxml
Propulsé par Django
xhtml 1.0
css 2.1
884 membres
1440 sujets
11337 messages
Dernier membre inscrit: Saidov17
166 invités en ligne
membre en ligne: -
RSS Feed