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

Delphi Discussion :

Lecture d'un fichier binaire


Sujet :

Delphi

  1. #1
    Membre à l'essai
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2012
    Messages
    10
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Service public

    Informations forums :
    Inscription : Octobre 2012
    Messages : 10
    Points : 11
    Points
    11
    Par défaut Lecture d'un fichier binaire
    Bonjour,

    je cherche à lire un fichier binaire écrit je pense en C.

    Je n'ai pas de problème pour le lire mais pour une partie j'ai un résultat qui n'est pas conforme aux données que j'attends.

    Les données codées sont des identifiants de stations topographiques de la forme

    1, 2, 3 ..... n

    ou 1.1, 1.2, 1.3 ..., 2.1, 2.2, 2.3, ...., n.m

    avec n et m entiers positifs.

    Le concepteur du logiciel qui génère ces fichiers a fourni le commentaire suivant sur le codage du fichier :

    // station identification
    Int32 value // 0x80000000: undefined, <0: plain numbers + 0x80000001, >=0: major<<16|minor

    All integers little endian.


    J'ai écrit le code suivant pour récupérer ces valeurs :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function LisId: string;
     
    var  w1,w2: word;
     
    begin
      LireBuffer(w1, sizeof(word));
      LireBuffer(w2, sizeof(word));
      if w2 > 32767 then w2 := 0;
      if W2 > 0 then result := IntToStr(W2) + '.' + IntToStr(W1);
      else result := IntToStr(W1);
    end;
    Lorsque l'identifiant est formé d'un seul chiffre, j'obtiens la valeur n+1. Dans l'autre cas c'est correct.
    Je le corrige en renvoyant dans ce cas n-1 mais j'aimerai comprendre si j'ai fait une erreur ou s'il y a une meilleure façon d'écrire ce code ?

    Merci d'avance pour votre réponse

  2. #2
    Membre émérite
    Avatar de ALWEBER
    Homme Profil pro
    Expert Delphi
    Inscrit en
    Mars 2006
    Messages
    1 509
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 69
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Expert Delphi

    Informations forums :
    Inscription : Mars 2006
    Messages : 1 509
    Points : 2 782
    Points
    2 782
    Billets dans le blog
    10
    Par défaut
    Tu dois partir plutôt d'un TStream ou de l'un de ses dérivés (FileStream, TMemoryStream,...)
    Si tu nous donnes un exemple on peut peut être te donner une solution. Le codage des octets est certainement inversé (Little indian)

  3. #3
    Modérateur
    Avatar de tourlourou
    Homme Profil pro
    Biologiste ; Progr(amateur)
    Inscrit en
    Mars 2005
    Messages
    3 885
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Biologiste ; Progr(amateur)

    Informations forums :
    Inscription : Mars 2005
    Messages : 3 885
    Points : 11 403
    Points
    11 403
    Billets dans le blog
    6
    Par défaut
    Une bizarrerie me semble être la lecture de Word, entiers positifs codés sur 2 octets (uint16) pour lire des valeurs entières signées codées sur 4 octets (int32)...

  4. #4
    Membre à l'essai
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2012
    Messages
    10
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Service public

    Informations forums :
    Inscription : Octobre 2012
    Messages : 10
    Points : 11
    Points
    11
    Par défaut
    je me sers des deux variable w1 et w2 pour lire les deux parties du int32. D'ailleurs ça marche bien, sauf dans le cas où w2 est > 32767, auquel cas la première partie est supérieure de 1 a sa valeur

    sinon, peux-tu me dire comment traiter un Int32 pour retrouver les deux valeurs selon ce qu'a indiqué le développeur ?

    // station identification
    Int32 value // 0x80000000: undefined, <0: plain numbers + 0x80000001, >=0: major<<16|minor

  5. #5
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 830
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 830
    Points : 13 574
    Points
    13 574
    Par défaut
    Lire word par word est une mauvaise idée.
    Il est dit que la donnée représente le numéro de station plus un offset de $80000001. Donc pour retrouver le numéro de station il faut soustraire cet offset : NuméroDeStation = Donnée -$80000001.

    En traitant la donnée tronquée telle-quelle, tu es décalé du LoWord de l'offset, soit 1.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    function LisId: string;
    var  
      Data :integer;
     
    begin
      LireBuffer(Data, sizeof(Data));
     
      case Data of
        $80000000     : Result := 'Indéfini';  
        $80000001..-1 : Result := IntToStr(Data -integer($80000001));
        else            Result := Format('%d.%d', [HiWord(Data), LoWord(Data)]);
      end;
    end;
    J'ai mis directement des valeurs mais $80000000 pourrait aussi être écrit Low(Integer), $80000001 Low(Integer)+1, etc.

  6. #6
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 457
    Points
    28 457
    Par défaut
    Citation Envoyé par Topo38 Voir le message
    je me sers des deux variable w1 et w2 pour lire les deux parties du int32. D'ailleurs ça marche bien, sauf dans le cas où w2 est > 32767, auquel cas la première partie est supérieure de 1 a sa valeur

    sinon, peux-tu me dire comment traiter un Int32 pour retrouver les deux valeurs selon ce qu'a indiqué le développeur ?

    // station identification
    Int32 value // 0x80000000: undefined, <0: plain numbers + 0x80000001, >=0: major<<16|minor
    c'est exactement ce qui est indiqué

    soit tu as major et minor dans w1 et w2, soit tu as $8000 dans w2 et "number + 1" dans w1

    mais je suppose que "plain numbers" n'est pas limité à 16 bits, du coup ce serait ((w2 and $7FFF) shl 16 + w1) - 1

    ou encore, et si je ne m'abuse

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    type
      TStationId = record
      case Byte of
        0: (Raw: Cardinal);
        1: (Major, Minor: Word);
        2: (NegNumber: Integer); // - 1 - Number, donc Number = - NegNumber - 1
      end;

  7. #7
    Membre à l'essai
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2012
    Messages
    10
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Service public

    Informations forums :
    Inscription : Octobre 2012
    Messages : 10
    Points : 11
    Points
    11
    Par défaut
    merci pour ta réponse et tes explications

    J'ai simplement corrigé le code comme ci-dessous (pour Delphi 7) et ça marche bien

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    function LisId: string;
    var  
      Data :integer;
     
    begin
      LireBuffer(Data, sizeof(Data));
     
      case Data of
        $80000000     : Result := 'Indéfini';
        integer($80000001)..-1 : Result := IntToStr(Data -integer($80000001));
        else            Result := Format('%d.%d', [HiWord(Data), LoWord(Data)]);
      end;
    end;

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

Discussions similaires

  1. Réponses: 1
    Dernier message: 21/12/2006, 14h06
  2. lecture d'un fichier binaire
    Par booby dans le forum C
    Réponses: 17
    Dernier message: 20/09/2006, 17h11
  3. lecture d'un fichier binaire
    Par Tonta dans le forum C++
    Réponses: 1
    Dernier message: 14/04/2006, 07h53
  4. lecture d'un fichier binaire en VB
    Par olivier] dans le forum VB 6 et antérieur
    Réponses: 7
    Dernier message: 28/12/2005, 12h17
  5. Lecture d'un fichier binaire
    Par Gloubie dans le forum Langage
    Réponses: 9
    Dernier message: 05/12/2005, 13h51

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