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 :

Lecture de fichiers binaires


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    42
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 42
    Par défaut Lecture de fichiers binaires
    Bonjour,

    J'ai un gros soucis. Je m'explique:

    J'essaye depuis un moment déja de lire des fichiers binaires avec un format particulier. En effet ces fichiers sont écrits à l'aide d'un programme Java ( donc big endian ) de plus il y a des entiers codés sur 3 octets and co.

    Le soucis c est que je n'arrives pas , même avec des exemples a comprendre et à faire fonctionner.
    Le format du fichiers est le suivant :
    -1 header de 8192 bytes décomposés en 2 parties servant d'index de données:
    -Une première section de 4096 octets composé de 1024 séries de 4 octets
    les 3 premiers octets donnent l'offset et le dernier donnant le nombre de secteurs des données ( 1 secteur = 4096 octets )

    -Une deuxième section compressant 1024 séries de 4 octets donnant le timetstamp depuis la dernière modification des données ( 4 octets )

    -le reste du fichiers étant les données donc l'index est fourni grâce aux headers.

    Pour info, ce sont la structure des fichiers "regions" de minecraft. Des infos plus claires sur la structure du fichiers est dispo à cette adresse.

    Si quelqu'un pouvez m expliquer comment je dois m y prendre parce que ca m ennuie vraiment. J'ai tout essayé avec des streams ( donc facon c++) avec des FILE facon c, en mélangeant les deux.
    A chaque fois je me retrouver avec des retours totalement foireux genre des offsets plus grand que le fichiers lui meme et d autres joyeusetés.

    J'ai l impression que c est peux être du au faites que le fichier est écrit en java parce je n ai jamais eu ce genre de problèmes.
    Pour information je sous VS2010 ( quelque fois que cela change quelque chose ).

    Cordialement Mathieu

  2. #2
    Membre très actif
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    176
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 176
    Par défaut
    Hello,

    Tu peux déjà poster ce que tu as fait pour qu'on ne parte pas d'un truc "vide".

    Tu peux aussi jeter un œil à cet article . ça pourra peut-être aider.

  3. #3
    Membre éclairé Avatar de aslo92
    Homme Profil pro
    Ingénieur développement logiciels temps réel
    Inscrit en
    Février 2012
    Messages
    43
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels temps réel
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2012
    Messages : 43
    Par défaut
    Bonjour lange59,

    d'après ce que j'ai compris je pense que le code suivant doit être assez proche de ce que tu veux faire:

    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
    #include <cstdlib>
    #include <iostream>
     
    using namespace std;
     
    inline void endian_swap(unsigned int& x)
    {
        x = (x>>24) | 
            ((x<<8) & 0x00FF0000) |
            ((x>>8) & 0x0000FF00) |
            (x<<24);
    }
     
    int read(char* filename)
    {
        int length;
        char * buffer;
     
        ifstream is;
        is.open(filename), ios::binary);
     
        // Obtenir la taille du fichier
        is.seekg(0, ios::end);
        length = is.tellg();
        is.seekg(0, ios::beg);
     
        // Allouer de la mémoire pour le fichier
        buffer = new char [length];
        if (buffer != NULL)
        {
            // Ecrire les données en mémoire
            is.read (buffer,length);
            is.close();
     
            // Conversion big endian vers little endian
            unsigned int* pui_buffer = (unsigned int*)buffer;
            unsigned int  data       = pui_buffer[0];
     
            endian_swap(data);
     
            // Extraction de l'offset
            unsigned int offset = data >> 8;
     
            // Extraction du nombre de secteurs
            unsigned int num_sect = data & 0x000000FF;
     
            // Continuer la lecture du buffer de la même façon en incrémentant l'index pour passer aux 4 octets suivants...
     
            // Libérer la mémoire une fois le traitement terminé
            delete[] buffer;
        }
        else
        {
            return 0;
        }
     
        return 1;
    }
    Je lis le fichier au complet (tu peux lire seulement le début (header) également) puis je converti les 4 premiers octets en little endian pour avoir un entier avec des octets dans le bon ordre.

    Ensuite un décalage à droite de 8 bits me permet de récupérer les 3 premiers octets (offset).

    Un masque sur le 4eme octet me permet de récupérer le nombre de secteurs.
    Si ça ne marche pas essaye de ne pas faire la conversion en little endian. Peut-être que les octets sont bien ordonnés dès la lecture?


    Je n'ai pas ajouté de test sur l'ouverture du fichier pour ne pas alourdir le code.

  4. #4
    Membre averti
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    42
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 42
    Par défaut
    Bonjour,

    Pour l'instant j'ai ceci:
    Je lis le header que je stock et que j'utilise pour lire l offset et le nombre de secteur du "chunk" ( un chunk étant un tableau de bytes compressé avec la zlib )).

    Le détail exact de la structure du fichier:

    Region File Format

    Concept: The minimum unit of storage on hard drives is 4KB. 90% of Minecraft
    chunks are smaller than 4KB. 99% are smaller than 8KB. Write a simple
    container to store chunks in single files in runs of 4KB sectors.

    Each region file represents a 32x32 group of chunks. The conversion from
    chunk number to region number is floor(coord / 32): a chunk at (30, -3)
    would be in region (0, -1), and one at (70, -30) would be at (3, -1).
    Region files are named "r.x.z.data", where x and z are the region coordinates.

    A region file begins with a 4KB header that describes where chunks are stored
    in the file. A 4-byte big-endian integer represents sector offsets and sector
    counts. The chunk offset for a chunk (x, z) begins at byte 4*(x+z*32) in the
    file. The bottom byte of the chunk offset indicates the number of sectors the
    chunk takes up, and the top 3 bytes represent the sector number of the chunk.
    Given a chunk offset o, the chunk data begins at byte 4096*(o/256) and takes up
    at most 4096*(o%256) bytes. A chunk cannot exceed 1MB in size. If a chunk
    offset is 0, the corresponding chunk is not stored in the region file.

    Chunk data begins with a 4-byte big-endian integer representing the chunk data
    length in bytes, not counting the length field. The length must be smaller than
    4096 times the number of sectors. The next byte is a version field, to allow
    backwards-compatible updates to how chunks are encoded.

    A version of 1 represents a gzipped NBT file. The gzipped data is the chunk
    length - 1.

    A version of 2 represents a deflated (zlib compressed) NBT file. The deflated
    data is the chunk length - 1.
    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
     
    inline bool readData()
    {
    	header.reset(new char[8192]);
    	strm.read(header.get(), 8192);
    	return true;
    }
     
    inline sChunkIndex readChunkIndex(int xChunk, int yChunk)
    {
    	sChunkIndex index;
     
    	index.offset = readChunkOffset(xChunk, yChunk);
    	index.sectorCount = readChunkSectorCount(xChunk, yChunk);
    	index.timestamp = readChunkTimestamp(xChunk, yChunk);
     
    	return index;
    }
     
    inline int readChunkOffset(int xChunk, int yChunk)
    {
    	unsigned char buff[3];
    	int o = 4 * ((xChunk % 32) + (yChunk % 32) * 32);
     
    	std::cout << o << std::endl;
    	buff[0] = header.get()[o];
    	buff[1] = header.get()[o+1];
    	buff[2] = header.get()[o+2];
     
    	return ( buff[0]<<16 | buff[1]<<8 | buff[2] );
    }
     
    inline int readChunkSectorCount(int xChunk, int yChunk)
    {
    	int o = 4 * ((xChunk % 32) + (yChunk % 32) * 32);
     
    	std::cout << o << std::endl;
    	return (int)(header.get()[0+3]);
    }
     
    inline int readChunkTimestamp(int xChunk, int yChunk)
    {
    	unsigned char buff[4];
    	int o = 4 * ((xChunk % 32) + (yChunk % 32) * 32) + 4096;
     
    	std::cout << o << std::endl;
     
    	buff[0] = header.get()[o];
    	buff[1] = header.get()[o+1];
    	buff[2] = header.get()[o+2];
    	buff[3] = header.get()[o+3];
     
    	return ( buff[0]<<24 | buff[1]<<16 | buff[2] << 8 | buff[3] );
    }
     
    fs::path regionFile;
    fs::fstream strm;
    boost::scoped_array<char> header;
    Le problème avec ce code c est que les résultats sont aberrants, j 'ai l impression qu il y a un soucis mais je ne sais pas lequel. Je suis en train de faire un programme java qui m ecrit un fichier avec ce format mais dont je connais tout les valeurs ( via l ecriture d'un fichier ) comme ça pour mes tests cela sera plus simple parce que ca devient une véritable galère.

    Cordialement Mathieu

  5. #5
    Membre Expert
    Homme Profil pro
    Inscrit en
    Décembre 2010
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 734
    Par défaut
    Est-ce que par hasard ce ne serait pas que tu programmes en environnement little-endian et que tu n'inverses pas les octets, alors que la JVM est un environnement big-endian? Si tu veux quelque chose de portable, il me semble qu'il faut utiliser ntoh, qui inverse ou pas en fonction des environnements

  6. #6
    Membre averti
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    42
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 42
    Par défaut
    Bonjour,

    Justement c est ce que je pense mais normalement j'inverse les bytes via les opérateurs de décalage, ça devrait être bon. tout les codes d exemples que j ai trouvé utilise cette technique de décalage ou ntoh.
    Mais d'après ce que j ai trouvé, c est sensiblement pareil.

    Je comprend pas du tout.

    Cordialement Mathieu

  7. #7
    Membre éclairé Avatar de aslo92
    Homme Profil pro
    Ingénieur développement logiciels temps réel
    Inscrit en
    Février 2012
    Messages
    43
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels temps réel
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2012
    Messages : 43
    Par défaut
    D'après le format que tu donnes, j'aurai codé comme ça:

    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
     
    inline unsigned int readChunkOffset(int xChunk, int yChunk)
    {
    	unsigned int buff = 0;
    	unsigned char* data = (unsigned char*)&buff;
    //	int o = 4 * ((xChunk % 32) + (yChunk % 32) * 32);
    	int o = 4 * (xChunk + yChunk * 32);
     
    	std::cout << o << std::endl;
    	data[2] = header.get()[o];
    	data[1] = header.get()[o+1];
    	data[0] = header.get()[o+2];
     
    	return buff;
    }
     
    inline unsigned int readChunkTimestamp(int xChunk, int yChunk)
    {
    	unsigned int buff = 0;
    	unsigned char* data = (unsigned char*)&buff;
    //	int o = 4 * ((xChunk % 32) + (yChunk % 32) * 32) + 4096;
    	int o = ((4 * (xChunk + yChunk * 32)) % 256) * 4096;
     
    	std::cout << o << std::endl;
     
    	data[3] = header.get()[o];
    	data[2] = header.get()[o+1];
    	data[1] = header.get()[o+2];
    	data[0] = header.get()[o+3];
     
    	return buff;
    }
    Cette manière de faire évite les décalages.
    Après si le résultat est faux, c'est sûrement à cause de la valeur calculée de o qui n'est pas la bonne. Tu peux utiliser un éditeur hexadécimal pour voir les données dans ton fichier. Ca te permettra de voir si tu lis bien au bon endroit.

    Après pour t'aider plus il me faudrait un fichier pour faire le test.

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

Discussions similaires

  1. Lecture de fichier binaire
    Par nuans dans le forum MATLAB
    Réponses: 23
    Dernier message: 21/05/2007, 10h00
  2. Lecture de fichier binaire et gestion de fin de fichier
    Par habasque dans le forum Entrée/Sortie
    Réponses: 2
    Dernier message: 02/05/2007, 17h06
  3. lecture ecriture fichier binaire
    Par jonckers dans le forum C++Builder
    Réponses: 2
    Dernier message: 27/04/2007, 09h12
  4. Réponses: 5
    Dernier message: 26/03/2007, 01h30
  5. lecture de fichier binaire
    Par Salim6 dans le forum C
    Réponses: 3
    Dernier message: 07/11/2005, 19h56

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