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 :

Le problème de sauvegarde de donnée binaire en C++ et la portabilité


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éprouvé
    Homme Profil pro
    sans activité
    Inscrit en
    Janvier 2016
    Messages
    76
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : sans activité

    Informations forums :
    Inscription : Janvier 2016
    Messages : 76
    Par défaut Le problème de sauvegarde de donnée binaire en C++ et la portabilité
    Suite à un problème d'écriture de données binaires, j'ai poser cette question erreur-wtf-lecture-fichier-binaire/. La réponse était simple et propre au chaine de caractères et au caractère terminateur.

    Mais du coup ce pose le problème des données binaires en C++ : Est-il possible de contourner (facilement et simplement) le problème des Little/Big Endian et également celui de la taille réelle des variables car même avec l'utilisation du style uint64_t je constate que le compilateur coupe la taille réelle des données en mémoire. Exemple si ma variable contient un petit nombre, inférieur à 256, la variable ne fait qu'un seul octet en mémoire.

    Je sais qu'il existe des librairies de "serialization" mais je cherche une solution sans librairies tierces.


    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
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    #include <fstream>
    #include <iostream>
     
    using namespace std;
     
    char* lire(const char* nomfichier)
    {
        int size;
        char * memblock = NULL;
     
        ifstream file (nomfichier, ios::in|ios::binary|ios::ate);
        if (file.is_open())
        {
        size = file.tellg();
     
    	//POUR TESTER LA TAILLE DE CE QUE J'ECRIS DANS LE FICHIER
    	cout << "size in read : " << size << endl;
     
    	memblock = new char [size];
     
        file.seekg (0, ios::beg);
     
    	//LECTURE DU FICHIER AVEC LA BONNE TAILLE VERIFIEE PLUS HAUT
    	file.read (memblock, size);
     
    	//ICI RIEN NE VA PLUS.... WTF
        cout << memblock << " : " << std::char_traits<char>::length(memblock) << '\n' << endl;
        file.close();
        }
        else cout << "Unable to open file";
     
        return memblock;
    }
     
    void ecrire(const char* nomfichier, const char* data)
    {
        int size;
        std::ofstream file (nomfichier, ios::out|ios::binary);
     
    	//TEST DE LA TAILLE EN ECRITURE -> OK
        size = std::char_traits<char>::length(data)+1;
        cout << "size in write : " << size << endl;
        file.write (data, size);
        file.close();
    }
     
    int main(int argc, char *argv[])
    {
        char* data;
        uint64_t* ui64;
        ui64 = new uint64_t(77);
        data = reinterpret_cast<char*>(ui64);
    	//TEST DE LA DONNEE ET DE SA TAILLE
        cout << data << " : " << std::char_traits<char>::length(data) << '\n' << endl;
     
        ecrire("test.txt", data);
     
        data = lire("test.txt");
     
        //LA REINTERPRETATION NE FONTIONNE PAS!!!
        *ui64 = reinterpret_cast<uint64_t>(data);
        cout << *ui64 << '\n' << endl;
        *ui64 = data[0];
        cout << *ui64 << '\n' << endl;
        cout << data << '\n' << endl;
     
     
        return 0;
    }

  2. #2
    Membre Expert

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2013
    Messages
    610
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Finance

    Informations forums :
    Inscription : Avril 2013
    Messages : 610
    Billets dans le blog
    21
    Par défaut
    Je n'ai pas l'opportunité de tester ton code, mais, avec tout le respect que je te dois, tu cumules les anti-patterns du C++: des cast à tout va, des new explicites, etc.
    Il me semble qu'il y a plutôt un problème de conception dans ton code.

    Il me semble que partir de fonctions template qui encapsulent tout ça rendrait la chose plus propre:

    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    template <typename T>
    std::ostream& serialize(const T& obj, std::ostream& os) {
      os.write(reinterpret_cast<const char*>(&obj), sizeof(T));
      return os;
    }
     
    template <typename T>
    std::istream& unserialize(T& obj, std::istream& os) {
      os.read(reinterpret_cast<char*>(&obj), sizeof(T));
      return os;
    }

    Naturellement cela reste assez basique: tu ne pourras pas serialiser un objet complexe comme un vector uniquement de cette façon (il faut prendre en compte aussi la région mémoire vers laquelle le pointeur qu'il contient pointe)

  3. #3
    Membre éprouvé
    Homme Profil pro
    sans activité
    Inscrit en
    Janvier 2016
    Messages
    76
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : sans activité

    Informations forums :
    Inscription : Janvier 2016
    Messages : 76
    Par défaut
    Aucun problème avec ta remarque stendhal666, mon code n'est opti du tout. Les templates était prévu mais je constate que j'ai déjà pas mal de problème avec mon code, je voulais déjà tester la logique de façon simple... Je dois aussi admettre que je suis débutant en C++ et n'ai pas encore tout les bons réflexes.

    Merci pour ton code.

  4. #4
    Membre Expert

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2013
    Messages
    610
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Finance

    Informations forums :
    Inscription : Avril 2013
    Messages : 610
    Billets dans le blog
    21
    Par défaut
    Ne me remercie pas trop vite... il ne marche pas! (je l'ai modifié un peu d'ailleurs)
    J'essaie de comprendre...

  5. #5
    Expert confirmé

    Avatar de dragonjoker59
    Homme Profil pro
    Software Developer
    Inscrit en
    Juin 2005
    Messages
    2 032
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Software Developer
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2005
    Messages : 2 032
    Billets dans le blog
    12
    Par défaut
    Pour le problème de Little/Big endian, tu peux écrire un "Magic Number" en tête de ton fichier, qui te permettra de détecter l'endianness du fichier, et donc de t'adapter en fonction.

    Ensuite, pour la découpe des données, autant avec les opérateurs << et >> j'ai constaté le soucis, autant avec read et write je ne l'ai plus eu.

    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
    37
    38
    39
    40
    41
    42
    #include <fstream>
    #include <iostream>
    #include <cstdint>
     
    template< typename T >
    std::ostream& serialize( T const & obj, std::ostream & os )
    {
      os.write( reinterpret_cast< char const * >( &obj ), sizeof( T ) );
      return os;
    }
     
    template< typename T >
    std::istream & unserialize( T & obj, std::istream & is )
    {
      is.read( reinterpret_cast< char * >( &obj ), sizeof( T ) );
      return is;
    }
     
    int main()
    {
      int64_t value;
      std::cin >> value;
      std::ofstream out( "tmp", std::ios::binary );
     
      if ( out )
      {
        std::cout << "Write value: " << value << std::endl;
        serialize( value, out );
        out.close();
      }
     
      std::ifstream in( "tmp", std::ios::binary );
      in.seekg( 0, std::ios::end );
      std::cout << "File size: " << in.tellg() << std::endl;
     
      if ( in )
      {
        unserialize( value, in );
        in.close();
        std::cout << "Read value: " << value << std::endl;
      }
    }
    Si vous ne trouvez plus rien, cherchez autre chose...

    Vous trouverez ici des tutoriels OpenGL moderne.
    Mon moteur 3D: Castor 3D, presque utilisable (venez participer, il y a de la place)!
    Un projet qui ne sert à rien, mais qu'il est joli (des fois) : ProceduralGenerator (Génération procédurale d'images, et post-processing).

  6. #6
    Membre éprouvé
    Homme Profil pro
    sans activité
    Inscrit en
    Janvier 2016
    Messages
    76
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : sans activité

    Informations forums :
    Inscription : Janvier 2016
    Messages : 76
    Par défaut
    dragonjoker59, je suis d'accord que Little/Big Endian est un faux problème auquel il existe des solutions, "Magic Number" en est une bonne.

    Je viens de tester ton code et effectivement le problème à disparu mais nous sommes d'accord que m^me si mon code n'est pas terrible, il n'est pas faux!

    Je ne sais pas quoi penser de cette bizarrerie...

  7. #7
    Membre éprouvé
    Homme Profil pro
    sans activité
    Inscrit en
    Janvier 2016
    Messages
    76
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : sans activité

    Informations forums :
    Inscription : Janvier 2016
    Messages : 76
    Par défaut
    MDR , je viens d'en trouver une autre!

    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
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    #include <fstream>
    #include <iostream>
    #include <cstdint>
     
    template< typename T >
    std::ostream& serialize( T const & obj, std::ostream & os )
    {
      os.write( reinterpret_cast< char const * >( &obj ), sizeof( T ) );
      return os;
    }
     
    template< typename T >
    std::istream & unserialize( T & obj, std::istream & is )
    {
      is.read( reinterpret_cast< char * >( &obj ), sizeof( T ) );
      return is;
    }
     
    struct Test_div_ui
    {
        int64_t value64;
        int32_t value32;
    };
     
    int main()
    {
      Test_div_ui tdui;
      //std::cin >> value;
      tdui.value32 = 77;
      tdui.value64 = 77;
      std::ofstream out( "tmp", std::ios::binary );
     
      if ( out )
      {
        std::cout << "Write value: " << tdui.value32 << ", " << tdui.value64 << std::endl;
        serialize( tdui, out );
        out.close();
      }
     
      std::ifstream in( "tmp", std::ios::binary );
      in.seekg( 0, std::ios::end );
      std::cout << "File size: " << in.tellg() << std::endl;
     
      if ( in )
      {
        unserialize( tdui, in );
        in.close();
        std::cout << "Read value: " << tdui.value32 << ", " << tdui.value64 << std::endl;
      }
    }

    La taille du fichier ne fait pas 12 mais 16 octets!

Discussions similaires

  1. Réponses: 2
    Dernier message: 26/05/2011, 22h06
  2. [1.x] Problème de sauvegarde des données avec embed form
    Par Vicrabb dans le forum Symfony
    Réponses: 2
    Dernier message: 24/11/2010, 12h11
  3. [MySQL] problème de sauvegarde de données dans la base MySQL
    Par hassen07 dans le forum PHP & Base de données
    Réponses: 4
    Dernier message: 27/05/2010, 21h58
  4. Réponses: 2
    Dernier message: 19/09/2007, 21h00
  5. Problème pour sauvegarder mes données
    Par ploup dans le forum Windows Forms
    Réponses: 5
    Dernier message: 04/05/2007, 14h17

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