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 :

Problème de lecture de fichiers binaires


Sujet :

C++

  1. #1
    Membre à l'essai
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2013
    Messages
    16
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2013
    Messages : 16
    Points : 23
    Points
    23
    Par défaut Problème de lecture de fichiers binaires
    Bonjour,

    Dans mon programme, j'ouvre des fichiers binaires (qui sont des images). Certain fichiers ont les valeurs codées sur 1 octet d'autres sur 2 et enfin d'autres sur 4.

    J'ai donc voulu écrire un Loader qui permet en renseignant le nombre d'octets sur lesquelles les valeurs sont codés de charger les données de l'image pour les mettre dans un vecteur de floats (car après je travaille avec des images flottantes.
    C'est à ce moment que j'ai un problème :

    Pour faire une fonction qui est générique, je bricole en déclarant la fonction template pour le nombres d'octets lus :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    template<typename T>
    static vector<float> *LoadFile(char const * fileName, T nbBytes)
    Je fais ça car quand je lis le fichier je procède ainsi :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
                while (i<vecSize) //vecSize est la taille du fichier binaire/nbBytes
                {
                    T val;
                    inFile.read(reinterpret_cast<char*>(&val), nbBytes);
                    (*res)[i] = float(val);
                    ++i;
                }
    Je n'ai pas l'impression de bien programmer en faisant ça . D'autant que pour l'appel de fonction ça devient par exemple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    vector<float> *rawData = RawDataLoader::LoadFile(mask.c_str(),(float)4);
    //ou
    vector<float> *rawData = RawDataLoader::LoadFile(mask.c_str(),(unsigned char)1);
    Je ne sais pas le faire correctement donc si vous avez des pistes svp ?

    Pour le code complet de la fonction :
    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
     
       template<typename T>
        static vector<float> *LoadFile(char const * fileName, T nbBytes)
        {
            ifstream inFile(fileName, ifstream::binary);
     
            if (inFile)
            {
                inFile.seekg(0, inFile.end);
                int length = inFile.tellg();
                inFile.seekg(0, inFile.beg);
                cout << "length is " << length << endl;
     
                size_t vecSize = length/nbBytes;
     
                vector<float> *res = new vector<float>(vecSize);
                unsigned int i = 0;
                while (i<vecSize)
                {
                    T val;
                    inFile.read(reinterpret_cast<char*>(&val), nbBytes);
                    (*res)[i] = float(val);
                    ++i;
                }
                inFile.close();
                return res;
            }
            else
            {
                cerr << "When openning " << fileName << " : no such file or directory" << endl;
                exit(1);
            }
        }

  2. #2
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    J'ai du mal à voir pourquoi le nombre d'octets à lire devrait être générique, plutôt que le type size_t.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  3. #3
    Membre à l'essai
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2013
    Messages
    16
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2013
    Messages : 16
    Points : 23
    Points
    23
    Par défaut
    J'ai du mal à voir pourquoi le nombre d'octets à lire devrait être générique, plutôt que le type size_t.
    J'avais un problème lors de la lecture :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
        T val;
        inFile.read(reinterpret_cast<char*>(&val), nbBytes);
        (*res)[i] = float(val);
    Si je met le mauvais type à val, ça me donne des valeurs fausse. Je pensais mettre le bon type à val en le déterminant avec le type de nbBytes. En fait c'est comme si je veux passer en paramètre un type (et non pas une valeur). C'est pour ça que j'ai mis le nombre d'octec en T.

  4. #4
    Membre régulier
    Profil pro
    Ingénieur
    Inscrit en
    Avril 2013
    Messages
    77
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur

    Informations forums :
    Inscription : Avril 2013
    Messages : 77
    Points : 107
    Points
    107
    Par défaut
    Oui voilà, moi aussi j'aurai mis un size_t.

    Du coup, il serait peut être plus judicieux d'utiliser la fonction get() en indiquant la taille voulue (le size_t paramétrable).
    A partir de là, tu récupères la chaîne avec 1, 2 ou 4 octets... et tu peux utiliser strtol pour la convertir en base 16.

  5. #5
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    On ne peut pas se baser sur la taille seule, car int et float tendent à faire tous les deux 32 octets.

    Le plus simple pour des templates, c'est un truc de ce genre:
    Code C++ : 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
    template< class T >
    void read(T* buf, size_t nbElems)
    {
    	size_t nbBytes = nbElems*sizeof(T);
    	inFile.read(reinterpret_cast<char*>(buf), nbBytes);
    }
    template< class T, size_t N >
    void read(T (&buf)[N]))
    {
    	read(&buf[0], N);
    }
    //EDIT
    template< class T >
    void read(std::vector<T> &buf)
    {
    	read(&buf[0], buf.size());
    }
    En typage statique, il est avantageux de passer la destination par pointeur ou référence plutôt que la retourner, car ça permet de déterminer le type à partir des paramètres.

    Après, si tu veux que ton typage soit carrément dynamique, ça va être beaucoup plus dur.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  6. #6
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Bonjour,


    - pourquoi allouer dynamiquement un vector ?
    - pourquoi ne pas lire tout simplement le fichier en une fois ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    inFile.read(reinterpret_cast<char*>(&val), nbBytes);
                    (*res)[i] = float(val);
    Si c'est juste pour lire tout à la suite dans l'ordre et les mettre dans un vector, aucun intérêt à ne pas le faire vraiment en une fois
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    std::vector<float> vec;
    vec.resize(infile.gcount() /* / sizeof(float) ?*/);
    infile.read(&(vec[0]));
    A la louche
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  7. #7
    Membre à l'essai
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2013
    Messages
    16
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2013
    Messages : 16
    Points : 23
    Points
    23
    Par défaut
    Tout d'abord merci pour vos réponses


    - pourquoi allouer dynamiquement un vector ?
    Parce que je manipule ensuite des images qui ont des vector<T> *data (pour les valeurs des voxels).


    - pourquoi ne pas lire tout simplement le fichier en une fois ?
    Dans la solution que tu proposes, si les données sont codées sur 1 octet par exemple (ou sur un nombre différent d'octets que pour un float), lire tout le fichier pour l'écrire dans vec donne des valeurs fausses car il interprète les quatres premiers octets comme une seule valeur et non comme quatre (en tout cas c'est ce que j'ai compris).

    En fait la solution de Médinoc fonctionne et est mieux que ce que je faisais (du coup je lis tout en une fois), d'autant que je pourrai dans le futur travailler avec des images Int par exemple et non plus float donc voulir retourner un vector de float était stupide je pense.

  8. #8
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,
    Citation Envoyé par -Gesicht- Voir le message
    Parce que je manipule ensuite des images qui ont des vector<T> *data (pour les valeurs des voxels).
    Et pourquoi ne pas manipuler des images qui ont des vector<T> data pour les valeurs de voxels

    La classe std::vector est, justement, une classe RAIIsante qui permet de représenter des tableaux de taille dynamique de manière totalement transparente pour l'utilisateur.

    Cette classe est parfaitement copiable et assignable, et assure qu'il n'y aura pas de fuites mémoire lors de la destruction.

    Allouer dynamiquement la mémoire pour une instance de std::vector n'a strictement aucun sens: cela t'obligerait à t'inquiéter de qui est le vrai possesseur de l'instance afin de pouvoir la détruire quand elle devient inutile, et à veiller, le cas échéant, à ce que la copie et l'affectation de la classe qui utilise cette instance se fasse correctement.

    Si tu transmet une instance de std::vector sous la forme d'une référence constante dans le constructeur de la classe, que la classe manipule en interne une instance (qui sera une copie de celle passée en paramètre) de std::vector, tu n'as même plus besoin de t'inquiéter de respecter la règle des trois grands (si tu dois fournir une définition personnalisée pour une des fonctions parmi le constructeur par copie, l'opérateur d'affectation ou le destructeur, tu dois fournir une définition personnalisée pour les trois), car le constructeur par copie, l'opérateur d'affectation et le destructeur fournis par le compilateur font parfaitement leur boulot
    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

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

Discussions similaires

  1. Problème lecture de fichier binaire
    Par -N4w4k- dans le forum C#
    Réponses: 3
    Dernier message: 16/02/2013, 22h16
  2. Réponses: 7
    Dernier message: 31/10/2010, 15h39
  3. probléme lecture de fichier binaire octer par octet
    Par ousmanesidibe dans le forum C++
    Réponses: 2
    Dernier message: 12/12/2009, 21h34
  4. [POI] Problème de lecture des fichiers Word
    Par Dari dans le forum Documents
    Réponses: 9
    Dernier message: 05/07/2007, 14h08
  5. Réponses: 5
    Dernier message: 26/03/2007, 01h30

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