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

VB.NET Discussion :

Lecture fichier typé Delphi avec VB.Net


Sujet :

VB.NET

  1. #1
    Membre à l'essai
    Homme Profil pro
    Ingenieur
    Inscrit en
    Décembre 2013
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Ingenieur
    Secteur : Bâtiment Travaux Publics

    Informations forums :
    Inscription : Décembre 2013
    Messages : 4
    Par défaut Lecture fichier typé Delphi avec VB.Net
    Bonjour a tous,

    Je cherche a lire dans une appli VB.Net des fichiers typés créés a partir d'une appli developpée en Delphi.
    Ces fichiers sont composés de n records décrit comme ci dessus (extrait de code Delphi) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    TTargetData40 = record
        CycleMax: word; // Nombre de cycles out of range
        Kind: byte;
        Name: string[40];
        DateTime: double;
        HAngle: double; // angle Hz si kind = 0, direction si kind = 1
        VAngle: double; // angle V  si kind = 0, inclination si kind = 1
        D: double; // Distance
        Status: integer; // Statut
    end;
    Pour lire ces fichiers sous VB.Net, je me suis créé une Class équivalente au type Delphi décrit ci-dessus. J'ai ensuite écrit une procédure avec la fonction FileGetObject pour tenter de récuperer le contenu de ces fichiers :

    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
    Public Class BinData40
        Public CycleMax As Integer
        Public Kind As Integer
        <VBFixedString(40)> Public Name As String
        Public Datetime As Double
        Public Hangle As Double
        Public Vangle As Double
        Public D As Double
        Public Status As Integer
    End Class
     
    Public Sub ReadBinFile()
        Dim BinRec() As BinData40
        Dim nfic
        Dim strfilename As String = "C:\Monchemin ...\filetypeDelphi.bin"
        nfic = FreeFile()
        FileOpen(nfic, strFilename, OpenMode.Binary)
        FileGetObject(nfic, BinRec)
        FileClose(nfic)
    End Sub
    J'ai tenté plusieurs autres méthodes avec des BinaryReader, mais rien a faire, il m'est impossible de récuperer les records !

    J'en appelle a votre aide.
    Merci d'avance de vos réponses.

    (Je précise que je n'ai aucunes connaissances en Delphi, et que je ne suis pas un developpeur pro en VB.Net _ niveau moyen)

    [Edit:] Voici a quoi ressemble le contenu des fichiers BIN déchiffrés avec une appli Delphi.

    0 1 SERIALNUMBER 14/10/2013 00:10:55 0 0 100582 0
    ...
    0 0 C02RP50105s 14/10/2013 00:10:55 181.59953 102.79402 18.51655 0
    0 0 C02RP50106s 14/10/2013 00:10:55 208.45692 106.26708 16.817 0
    0 0 C02RP50107s 14/10/2013 00:10:55 0 0 0 1
    0 0 C02RP50108s 14/10/2013 00:10:55 220.98863 111.37649 6.66775 0
    0 0 C02RP50109s 14/10/2013 00:10:55 220.81178 89.56875 6.5956 0
    Fichiers attachés Fichiers attachés

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    J'ai tenté plusieurs autres méthodes avec des BinaryReader, mais rien a faire, il m'est impossible de récuperer les records !
    Qu'est-ce que tu as essayé exactement ? Et quels problèmes as-tu rencontrés ?
    Montre ton code, et les erreurs obtenues le cas échéant

  3. #3
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Bon, c'était un petit challenge amusant

    Je connaissais pas le format de fichier typé Delphi, donc j'ai fait du reverse engineering sur le fichier. Si je comprends bien, une string[40] occupe en fait 41 octets en mémoire (1 octet "préfixe" qui indique la longueur). Il y a des octets qui semblent ne servir à rien, c'est probablement du padding pour retomber sur des alignements de 8 octets. Le format de date m'a un peu laissé perplexe au début (je voyais pas trop comment on pouvait représenter une date par un double), mais en fait c'est le format OLE Automation, et il y a une méthode standard pour convertir ça en DateTime .NET.

    Voilà le résultat :

    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
     
    Dim records = ReadRecords("exemple_fichiertype_delphi.bin").ToList()
     
    ...
     
    Private Shared Iterator Function ReadRecords(ByVal path As String) As IEnumerable(Of Record)
        Using stream = File.OpenRead(path), reader = New BinaryReader(stream)
            While True
                Dim record As New Record()
                Try
                    record.CycleMax = reader.ReadUInt16()
                    record.Kind = reader.ReadByte()
                    Dim length = reader.ReadByte() ' préfixe de longueur de la chaine
                    Dim nameBytes = reader.ReadBytes(40)
                    record.Name = Encoding.ASCII.GetString(nameBytes, 0, length)
                    reader.ReadBytes(4) ' padding for alignment ?
                    record.DateTime = DateTime.FromOADate(reader.ReadDouble())
                    record.HAngle = reader.ReadDouble()
                    record.VAngle = reader.ReadDouble()
                    record.D = reader.ReadDouble()
                    record.Status = reader.ReadInt32()
                    reader.ReadBytes(4) ' padding ?
                Catch ex As EndOfStreamException
                    Return
                End Try
                Yield record
            End While
        End Using
    End Function
     
    Class Record
    	Public Property CycleMax() As UShort
    	Public Property Kind() As Byte
    	Public Property Name() As String
    	Public Property DateTime() As DateTime
    	Public Property HAngle() As Double
    	Public Property VAngle() As Double
    	Public Property D() As Double
    	Public Property Status() As Integer
    End Class

  4. #4
    Membre à l'essai
    Homme Profil pro
    Ingenieur
    Inscrit en
    Décembre 2013
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Ingenieur
    Secteur : Bâtiment Travaux Publics

    Informations forums :
    Inscription : Décembre 2013
    Messages : 4
    Par défaut
    Un grand merci tomlev pour votre aide!
    J'ai testé votre code ce la fonctionne parfaitement !

    Bon, c'était un petit challenge amusant
    La lecture de ces maudits fichiers a hanté mes journées au boulot depuis quelques mois, j'avais mis de coté ce developpement grace a vous je vais pouvoir me relancer !

    Qu'est-ce que tu as essayé exactement ? Et quels problèmes as-tu rencontrés ?
    En bon amateur que je suis je n'ai pas vraiment gardé de traces des mes précédents tests.
    Voici le type de résultats que j'obtenais (une ligne sans fin de code hexadecimale :
    0000010C53455249414C4E554D4245520000000000000000000000000000000000000000000000000000000000000000538C1A3E204BE44000000000.....
    J'ai visiblement encore pas mal de choses a apprendre du VB.Net...
    Je suis curieux, vous parlez de reverse engineering : avez-vous une technique particuliere (adapté a ce type de cas)? de la documentation sur le sujet ?

    Encore un grand merci pour votre aide

  5. #5
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Citation Envoyé par MatthieuT Voir le message
    Je suis curieux, vous parlez de reverse engineering : avez-vous une technique particuliere (adapté a ce type de cas)? de la documentation sur le sujet ?
    J'ai juste ouvert le fichier dans un éditeur hexadécimal, et j'ai comparé avec la déclaration Delphi du record en essayant de faire le lien entre les deux. En tâtonnant un peu j'ai fini par tomber juste

  6. #6
    Invité de passage
    Homme Profil pro
    Ingenieur topographe
    Inscrit en
    Février 2014
    Messages
    1
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Ingenieur topographe
    Secteur : Bâtiment

    Informations forums :
    Inscription : Février 2014
    Messages : 1
    Par défaut Remplacement de chaine de caractere a l'interieur du fichier bin
    Bonjour Thomas,

    Merci beaucoup pour ton aide concernant la lecture des fichiers bin en vb.net. Cela nous a ete tres utile (je travaille en effet en collaboration Matthieu).

    J'ai une autre question concernant ce probleme. Ce que je cherche a faire maintenant, c'est remplacer une chaine de caracteres presente dans le meme type de fichier bin par une autre chaine de caracteres.

    Exemple:

    Pour le type de fichier suivant: remplacer la chaine '14/10/2013 00:10:55' par '13/10/2013 20:10:55'

    Fichier .bin en entree:

    0 1 SERIALNUMBER 14/10/2013 00:10:55 0 0 100582 0
    ...
    0 0 C02RP50105s 14/10/2013 00:10:55 181.59953 102.79402 18.51655 0
    0 0 C02RP50106s 14/10/2013 00:10:55 208.45692 106.26708 16.817 0
    0 0 C02RP50107s 14/10/2013 00:10:55 0 0 0 1
    ...

    Fichier .bin desire en sortie:

    0 1 SERIALNUMBER 13/10/2013 20:10:55 0 0 100582 0
    ...
    0 0 C02RP50105s 13/10/2013 20:10:55 181.59953 102.79402 18.51655 0
    0 0 C02RP50106s 13/10/2013 20:10:55 208.45692 106.26708 16.817 0
    0 0 C02RP50107s 13/10/2013 20:10:55 0 0 0 1
    ...

    Y a-t-il une moyen de remplacer facilement la chaine de caracteres dans le meme style que la fonction remplacer du bloc note? Ou faut-il decoder (lire) le fichier puis le recoder (reecrire) après?
    J'essaie pour l'instant de faire de la lecture/ecriture mais il est vrai que je butte un peu sur la partie ecriture probablement a cause du padding.
    Du coup, la date est impactee puis tout ce qui suit, mais difficile de savoir si ca vient du probleme de date en lui meme ou a cause de l'espace.

    Voila, ce que j'ai pour l'instant:


    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
     
     
    Private Shared Sub WriteRecords(ByVal RecordBin As IEnumerable(Of RecordBIN)) 'As IEnumerable(Of RecordBIN)
     
            'Using stream = File.OpenRead(Path), reader = New BinaryReader(stream)
            Dim path As String 
            Dim Stream As New FileStream(path, FileMode.CreateNew)
            Dim writer = New BinaryWriter(Stream)
            Dim mySpace As String = "  "
            Dim SpaceBytes As Byte()
            SpaceBytes = System.Text.Encoding.Unicode.GetBytes(mySpace)
            Debug.Print(SpaceBytes.Length)
     
            Dim myNewDate As New System.DateTime(1996, 6, 3, 22, 15, 0)
            Dim newDate As String = myNewDate.ToOADate()
     
     
            'While True
            Try
                For Each line As RecordBIN In RecordBin
                    writer.Write(line.CycleMax)
                    writer.Write(line.Kind)
                    'Dim lengthName As Byte() = System.Text.Encoding.Unicode.GetBytes(line.Name.Length.ToString)
                    'writer.Write(lengthName)
                    writer.Write(line.Name)
                    writer.Write(SpaceBytes)
                    'writer.Write(newDate)
                    writer.Write(line.DateTime)
                    writer.Write(line.Hangle)
                    writer.Write(line.Vangle)
                    writer.Write(line.D)
                    writer.Write(line.Status)
                    writer.Write(SpaceBytes)
                Next
     
            Catch ex As EndOfStreamException
                'Return
     
            End Try
            'Yield RecordBin
            'End While
        End Sub
    Merci

  7. #7
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Citation Envoyé par Liky_82 Voir le message
    Y a-t-il une moyen de remplacer facilement la chaine de caracteres dans le meme style que la fonction remplacer du bloc note? Ou faut-il decoder (lire) le fichier puis le recoder (reecrire) après?
    Le problème est que dans le fichier, la date n'est pas sous forme de chaine de caractères mais sous forme binaire. Tu pourrais chercher la séquence binaire et la remplacer, mais dans un fichier binaire, c'est un peu risqué de faire comme ça, parce qu'il pourrait y avoir à un autre endroit une séquence identique qui ne veut pas du tout dire la même chose, vu que c'est lié à la position.

    Donc à mon avis le plus simple est de décoder, modifier la date, et recoder.

    C'est assez simple, c'est juste l'opération inverse de ReadRecords... Pour chaque opération Read dans la méthode ReadRecords, il faut que tu fasses un Write du même nombre d'octets dans la méthode WriteRecords, y compris les octets de padding :

    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
    Private Shared Sub WriteRecords(ByVal path As String, ByVal records As IEnumerable(Of Record))
        Using stream = File.Open(path, FileMode.Create, FileAccess.Write), writer = New BinaryWriter(stream)
            Dim encoder = Encoding.ASCII.GetEncoder()
            Dim padding(3) As Byte ' 4 bytes of padding
            For Each record in records
                writer.Write(record.CycleMax)
                writer.Write(record.Kind)
                writer.Write(CByte(record.Name.Length)) ' préfixe de longueur de la chaine
                Dim nameBytes(39) As Byte
                encoder.GetBytes(record.Name.ToCharArray(), 0, record.Name.Length, nameBytes, 0, True)
                writer.Write(nameBytes)
                writer.Write(padding)
                writer.Write(record.DateTime.ToOADate())
                writer.Write(record.HAngle)
                writer.Write(record.VAngle)
                writer.Write(record.D)
                writer.Write(record.Status)
                writer.Write(padding)
            Next
        End Using
    End Sub

Discussions similaires

  1. Lire les propriétés des fichiers Microsoft Office avec VB.net
    Par clementmarcotte dans le forum Contribuez
    Réponses: 0
    Dernier message: 03/04/2015, 05h35
  2. Problème lecture fichier en redirection avec foreach
    Par nicnictout dans le forum Langage
    Réponses: 25
    Dernier message: 07/01/2011, 16h11
  3. lecture fichier disque dur avec caractères spéciaux.
    Par faitgaffe dans le forum Langage
    Réponses: 1
    Dernier message: 14/03/2010, 20h48
  4. Fichiers typés delphi 7 (débutant)
    Par tremeur53 dans le forum Débuter
    Réponses: 8
    Dernier message: 26/10/2006, 22h57
  5. [Debuter] Delphi avec Visual .NET 2005
    Par kacedda dans le forum Delphi
    Réponses: 4
    Dernier message: 24/05/2006, 13h37

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