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 :

Ecriture dans un fichier binaire


Sujet :

C++

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Août 2010
    Messages
    4
    Détails du profil
    Informations personnelles :
    Âge : 52
    Localisation : France

    Informations forums :
    Inscription : Août 2010
    Messages : 4
    Par défaut Ecriture dans un fichier binaire
    Bonjour,

    Je développe dans quelques langages, mais je débute en C++.
    J'essaie de créer et copier des fichiers bitmap à partir d'une classe Bitmap en utilisant des structures des différents headers d'une image bitmap.
    Le programme fonctionne presque, j'ai juste un problème au niveau du premier header :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    typedef struct {
    //    unsigned short type;            /* Les caractères "BM" qui indiquent le type du fichier */
        unsigned char type1;            /* Les caractères "BM" qui indiquent le type du fichier */
        unsigned char type2;            /* Les caractères "BM" qui indiquent le type du fichier */
     
        unsigned int size;              /* La taille totale du fichier */
        unsigned short reserved1;       /* réservé pour stocker l'application d'origine */
        unsigned short reserved2;       /* réservé pour stocker l'application d'origine */
        unsigned int offset;            /* Adresse de l'offset où commence le stockage des pixels de l'image */
    } BmpFileHeader;
    Quand j'initialise mon objet bitmap de cette façon (où FH est de type BmpFileHeader) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    //    this->FH.type=19778;//=>BM
        this->FH.type1='\x42';//=>B
        this->FH.type2='\x4D';//=>M
        this->FH.size=(unsigned int)(this->IH.height*this->IH.width*3+54);//dans l'exemple, 120054
    Je me retrouve dans mon fichier avec ces octets suivants :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    42 4D 3B 00 F6 D4 01 00
    au lieu de :
    J'ai remplacé la variable initiale type de type unsigned short par deux variables de type char, le problème reste le même.
    J'ai vérifié la taille des char, short et int avec des sizeof, mais ça correspond bien à ce qui est attendu (1 pour le char, 2 pour le short et 4 pour les int).
    Si je modifie l'ordre des variables dans la structure, il y a toujours 2 octets en plus après les octets 42 4D.
    Si je vire les deux octets en trop, mon fichier est bien interprété et affiché comme une image bitmap.

    Je travaille sous Windows avec NetBeans ou DevCpp.

    Si quelqu'un a une idée, je suis preneur, je ne sais pas d'où peuvent venir ces octets supplémentaires.

    Merci d'avance.

  2. #2
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 638
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 638
    Par défaut
    Salut, et bienvenue sur le forum.

    Ce qui serait sympa, c'est que tu nous donnes le code d'écriture dans le fichier, car, autrement, nous auront les plus grosse difficultés pour t'aider
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Août 2010
    Messages
    4
    Détails du profil
    Informations personnelles :
    Âge : 52
    Localisation : France

    Informations forums :
    Inscription : Août 2010
    Messages : 4
    Par défaut
    oups, désolé...
    voici le code que j'utilise pour écrire dans le fichier :
    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
     
    int Bitmap::save(char* dest){
     
        ofstream myBmpFile(dest,ios::out|ios::binary);
     
        if(!myBmpFile)
                {
                cerr<<"File Could not be Opened."<<endl;
                exit(1);
                }
     
        myBmpFile.write((char*)(&this->FH),sizeof(this->FH));
        myBmpFile.write((char*)(&this->IH),sizeof(this->IH));
     
    ...
     
    }
    Ce qui m'étonne le plus, ce que tout le reste fonctionne, le deuxième header (this->IH) est écrit correctement, ainsi que le tableau de pixels qui suit... Il n'y a que les octets correspondant au "BM" qui posent problème.

  4. #4
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 638
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 638
    Par défaut
    Pourquoi faire simple quand on peut faire compliqué

    Si tu as bel et bien la structure
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    /* NOTA: en C++, la définition du corps d'une structure, d'une
     * classe, d'une union ou d'une énumération crée automatiquement
     * le type associé... le typedef est donc inutile :D
     */
    struct BmpFileHeader{
    //    unsigned short type; 
        unsigned char type1;    
        unsigned char type2;
        unsigned int size;
        unsigned short reserved1;
        unsigned short reserved2;  
        unsigned int offset;
    };
    il faut savoir que la taille d'un (unsigned) char vaut... automatiquement 1 (c'est d'ailleurs la seule taille dont on puisse être sur pour les types primitif )

    De plus, le pointeur this est implicite dans les fonctions membres d'une classe.

    Tu pourrais donc écrire beaucoup plus simplement un code proche de
    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
    int Bitmap::save(char* dest){
     
        ofstream myBmpFile(dest,ios::out|ios::binary);
     
        if(!myBmpFile)
                {
                cerr<<"File Could not be Opened."<<endl;
                exit(1);
                }
     
        myBmpFile.write(&FH,1);
        myBmpFile.write(&IH),1);
        /* ou, si tu ne me crois pas sur la taille des char
         * myBmpFile.write(&FH,sizeof(char));
         * myBmpFile.write(&IH),sizeof(char));
         */
    ...
     
    }
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  5. #5
    Membre à l'essai
    Profil pro
    Inscrit en
    Août 2010
    Messages
    4
    Détails du profil
    Informations personnelles :
    Âge : 52
    Localisation : France

    Informations forums :
    Inscription : Août 2010
    Messages : 4
    Par défaut
    Merci pour ta réponse, j'ai simplifié un peu le code, je suis loin d'avoir tous les bons réflexes...

    En revanche, si j'écris :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     myBmpFile.write(&FH,1);
    le compilateur me dit qu'il ne reconnait pas le prototype de write, alors j'ai casté en char* :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     myBmpFile.write((char*)&FH,1);
    et là, ça passe.
    Mais, en toute logique, il ne m'écrit dans le fichier... que le premier caractère de chaque header.

    le write ne pose aucun problème pour le deuxième header. Chaque champ a la bonne taille et contient la bonne valeur. Dans le premier également, à part les deux octets qui suivent le "BM", tout le reste a la bonne taille et la bonne valeur.

    J'avais essayé de remplacer les deux char par une valeur en unsigned short, logiquement de taille identique aux deux char, mais ça ne changeait rien, je retrouvais toujours deux octets de trop entre les deux premiers champs du header...

  6. #6
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 638
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 638
    Par défaut
    Citation Envoyé par fjacquet Voir le message
    J'avais essayé de remplacer les deux char par une valeur en unsigned short, logiquement de taille identique aux deux char, mais ça ne changeait rien, je retrouvais toujours deux octets de trop entre les deux premiers champs du header...
    Attention, ma remarque était peut être un peu trop enfuie dans le reste pour que tu y prête attention, mais tu ne peux en aucun cas partir d'une quelconque idée préconçue quant à la taille des différents types primitifs...

    Les seules certitudes que l'on puisse avoir au niveau des types primitifs sont que:
    1. sizeof(char) = sizeof(unsigned char) = 1
    2. sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) (<= sizeof(long long) si d'application)
    3. sizeof(unsigned char) <= sizeof(unsigned short) <= sizeof(unsigned int) <= sizeof(unsigned long) (<= sizeof(unsigned long long) si d'application)
    Tu ne peux donc absolument pas te baser sur le fait qu'un (unsigned) short a la même taille que deux (unsigned) char parce que... ce n'est peut être pas le cas

    Si tu veux avoir la certitude qu'un champs de données prenne exactement la taille de deux (unsigned) char, il faut... utiliser un tableau de deux char

    Tu pourrais donc modifier ta structure sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    struct BmpFileHeader{
        unsigned char bmType[2];   
        unsigned int size;
        unsigned short reserved1;
        unsigned short reserved2;  
        unsigned int offset;
    };
    initialiser le champs sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    bmType[0]='B';
    bmType[1]='M';
    et l'écrire dans le fichier sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    myBmpFile.write(reinterpret_cast<unsigned char*>(bmType),2);
    Tu remarquera au passage que j'ai utilisé un autre transtypage, car... il vaut mieux éviter les cast "C style" (principalement pour faciliter la recherche, dans le cas présent )
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  7. #7
    Membre à l'essai
    Profil pro
    Inscrit en
    Août 2010
    Messages
    4
    Détails du profil
    Informations personnelles :
    Âge : 52
    Localisation : France

    Informations forums :
    Inscription : Août 2010
    Messages : 4
    Par défaut
    merci pour ta réponse., koala01.
    j'ai enfin réussi à écrire un header correct avec tes différents conseils...

    J'ai splitté mon premier header en deux :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    struct BmpFileId{
          unsigned char id[2];
     };
     
    struct BmpFileHeader {
        unsigned int size;             
        unsigned short reserved1;   
        unsigned short reserved2;  
        unsigned int offset;        
    } ;
    et j'ai repris tes cast pour écrire mes différents headers dans le fichier :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    myBmpFile.write(reinterpret_cast<char*>(&this->FI),2);
    myBmpFile.write(reinterpret_cast<char*>(&this->FH),sizeof(this->FH));
    le fait de bloquer à 2 le nombre d'octets écrits supprime bien les octets supplémentaires. En revanche, je ne sais toujours pas pourquoi 2 short dans une même structure n'ont pas la même taille une fois écrits dans un fichier
    ...

    Encore merci, bonne journée.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 1
    Dernier message: 24/06/2008, 14h11
  2. ecriture dans un fichier binaire
    Par Biosox dans le forum C++
    Réponses: 5
    Dernier message: 21/11/2007, 10h03
  3. Lecture ecriture dans un fichier binaire
    Par laetous dans le forum C
    Réponses: 13
    Dernier message: 26/08/2006, 08h50
  4. ouverture/lecture/ecriture dans un fichier en mode binaire
    Par dirty_boy dans le forum Débuter
    Réponses: 2
    Dernier message: 15/03/2006, 08h38
  5. [LG]ecriture dans un fichier binaire
    Par jsaviola dans le forum Langage
    Réponses: 3
    Dernier message: 26/12/2003, 17h30

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