Binärdaten auslesen mit VB.NET

  • VB.NET

Es gibt 18 Antworten in diesem Thema. Der letzte Beitrag () ist von RodFromGermany.

    Binärdaten auslesen mit VB.NET

    Hallo zusammen,

    ich bin zurzeit dabei ein altes VB6-Programm in VB.NET umzuschreiben, zu verbessern, Features hinzuzufügen, usw.
    Nun hänge ich an einer Datei, die in VB6 gespeichert wurde und nun in VB.NET geöffnet und gelesen werden soll. Die ersten und die letzten Zeilen kann ich problemlos auslesen. Zwischendrin habe ich jedoch einen Datensatz, bei dem es mit dem Format mal gar nicht stimmt.

    So wird's in VB6 gespeichert:

    Visual Basic-Quellcode

    1. Dim FileNum As Integer
    2. Dim N As Integer
    3. Dim Wert As Meßkoordinaten
    4. Dim Wert_Durch As Durchmesserwerte
    5. Private Sub Speichern_Click()
    6. '...
    7. MousePointer = 11
    8. Open Dateiname For Random As FileNum
    9. Call Save_Berechnung
    10. Close #FileNum
    11. MousePointer = 0
    12. '...
    13. End Sub
    14. Private Sub Save_Berechnung()
    15. Put #FileNum, 1, Dateikennung
    16. Put #FileNum, 2, Messdatum
    17. '....
    18. For i = 1 To Anzahl_Koordinaten_RAM3
    19. N = N + 1
    20. Wert.Punkt = Punkt_Nr(i)
    21. Wert.X_Wert = X_Koordinate(i) 'diese Werte kann ich nicht auslesen
    22. Wert.Y_Wert = Y_Koordinate(i)
    23. Wert.Z_Wert = Z_Koordinate(i)
    24. Put #FileNum, N, Wert
    25. Next i
    26. For i = 1 To Anzahl_Stationen
    27. N = N + 1
    28. Wert_Durch.Wert1 = Durchmesser_L_R(i) 'diese jedoch schon
    29. Wert_Durch.Wert2 = Durchmesser_R_R(i)
    30. Wert_Durch.Wert3 = Durchmesser_LR(i)
    31. Wert_Durch.Wert4 = Höhenkorrektur(i)
    32. Wert_Durch.Wert5 = Relativbewegung(i)
    33. Put #FileNum, N, Wert_Durch
    34. Next i
    35. '....
    36. End Sub


    So sind Meßkoordinaten und Durchmesserwerte definiert:

    Visual Basic-Quellcode

    1. Type Meßkoordinaten
    2. Punkt As Integer
    3. X_Wert As Double
    4. Y_Wert As Double
    5. Z_Wert As Double
    6. End Type
    7. Type Durchmesserwerte
    8. Wert1 As Single
    9. Wert2 As Single
    10. Wert3 As Single
    11. Wert4 As Single
    12. Wert5 As Single
    13. End Type


    So sieht ein Datensatz von den Koordinaten aus:
    30 200000 200000 100000
    31 161140,5 206518 99899,6
    32 170700,6 202696,2 99726,9
    usw.

    So sieht ein Datensatz von den Durchmessern aus:
    1993,9 1990,7 6411,5 -5,546 34,852
    usw.


    Und nun das ganz in VB.NET

    VB.NET-Quellcode

    1. Dim Datei As String = Datei_Pfad & "\" & Dateiname
    2. fileNum = FreeFile()
    3. FileOpen(fileNum, Datei, OpenMode.Random)
    4. Call Load_PSC()
    5. FileClose(fileNum)
    6. Sub Load_PSC()
    7. Dim N As Integer
    8. FileGet(fileNum, Dateikennung, 1)
    9. FileGet(fileNum, Messdatum, 2)
    10. For i = 1 To Anzahl_Koordinaten_RAM3
    11. N = N + 1
    12. FileGet(fileNum, Wert, N)
    13. Punkt_Nr(i) = Wert.Punkt
    14. X_Koordinate(i) = Wert.X_Wert 'diese Werte stimmen nicht
    15. Y_Koordinate(i) = Wert.Y_Wert
    16. Z_Koordinate(i) = Wert.Z_Wert
    17. Next
    18. For i = 1 To Anzahl_Stationen
    19. N = N + 1
    20. FileGet(fileNum, Wert_Durch, N)
    21. Durchmesser_L_R(i) = Wert_Durch.Wert1 'diese hingegen schon
    22. Durchmesser_R_R(i) = Wert_Durch.Wert2
    23. Durchmesser_LR(i) = Wert_Durch.Wert3
    24. Höhenkorrektur(i) = Wert_Durch.Wert4
    25. Relativbewegung(i) = Wert_Durch.Wert5
    26. Next
    27. '...
    28. End Sub



    So sehen dann die guten, alten Koordinaten aus (Punktnr, x-Wert, y-Wert, z-Wert):
    30 3.53278645668721E-310 3.53278645668721E-310 3.52939126342166E-310
    31 3.53177986860812E-310 -2.41356463899063E-185 3.52938606204523E-310
    -858980320 -2.41355850579437E-185 1.89119455317217E+185 3.52937711505615E-310
    -1717960671 4.68038614173845E-62 4.68039675961272E-62 3.52937523965949E-310

    Und so die Durchmesser (alles richtig):
    1993.9 1990.7 6411.5 -5.54698 34.85271
    1986.8 2000.6 6633.2 0 0
    1984.5 1971 6499.8 0 0


    Wo liegt das Problem? Ich versteh es nicht wirklich ?( . Ich hoffe ihr könnt mir weiterhelfen.
    Ich hab ganz ehrlich gesagt keinen Plan was du vor hast,
    weil es chronologisch absolut keinen Sinn ergibt, was du
    nun genau machen willst.

    Mach dir zuerst mal eine richtige detaillierte Beschreibung,
    was dein Vorhaben überhaupt schlussendlich erfüllen soll.
    Plane dir einen genauen Ablauf wie du das programmiertechnisch
    umsetzen willst.

    Informiere dich gründlich über die Unterschiede zweischen VB6
    und VB.Net. Nimm dazu das Internet und die Microsoft-Plattform.
    Eventuell bekommst du hier im Forum auch Unterstützung zum
    Thema VB6.

    Gehe Vb.net-Spezifisch vor, und vergiss am Besten Vb6.
    D.h. nicht irgendwelcher Code von Vb6 kopieren und in Vb.Net
    kopieren, sondern von grundauf solide Vb.Net technisch dein
    Vorhaben umsetzen.

    **********************************************************
    **********************************************************

    Da würde ich ungefähr so vorgehen
    (Man könnte auch Strukturen nehmen)
    - Klasse Messkoordinaten erstellen
    - Klasse Durchmesserwerte erstellen

    2 Methoden für die Files
    - SetFile(filename)
    - GetFile(filename)
    >> Wichtig: Die Dateien nicht offen lassen, wenn es nicht unbedingt sein muss

    2 Methoden für die Konvertierung
    - Convert Messkoordinaten
    - Convert Durchmesserwerte

    Und nun kannst du damit machen was du willst.

    Freundliche Grüsse

    exc-jdbi
    @tina83 Die Daten sehen aber eher nach Text-Daten aus.
    Also:
    Mach das Einlesen neu.
    Lies die Datei zeilenweise ein: IO.File.ReadAllLines(...)
    Mit
    For Each line As String in ALL_LINES_ARRAY
    oder
    For i = 0 To ALL_LINES_ARRAY.Length - 1
    iterierst Du Dich durch das Array durch.
    Dim parts = line.Spliot(" "c) zerlegt die Zeile in ihre Bestandteile
    und dann

    VB.NET-Quellcode

    1. Punkt_Nr(i) = parts(0)
    2. X_Koordinate(i) = parts(1)
    3. Y_Koordinate(i) = parts(2)
    4. Z_Koordinate(i) = parts(3)

    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    IO.File.ReadAllLines
    funktioniert doch nur mit ASCII-Formaten? Nicht aber mit binär-Dateien - soweit ich weiß

    mit IO.File.ReadAllLines bekomme ich die Datei nicht so geöffnet, dass ich diese lesen kann. Es sind nur kryptische Zeichen drin

    ich vermute um

    VB.NET-Quellcode

    1. fileNum = FreeFile()
    2. FileOpen(fileNum, Datei, OpenMode.Random)
    3. Call Load_PSC(Datei)
    4. FileClose(fileNum)

    werde ich nicht drumrum kommen, oder?
    @tina83 Poste mal bitte diese Datei, in eine ZIP verpackt.
    Erweiterte Antwort => Dateianhänge => Hochladen.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @tina83 OK, das sind Binärdaten.
    Poste mal bitte den Code, mit dem diese Daten erzeugt wurden.
    Steht oben, ich sehs mir mal an.
    Wahrscheinlich sind es nur die Dateitypen.

    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „RodFromGermany“ ()

    @tina83 Also dies:
    Basic 16 Bit oder Basic 32 Bit?
    Dateikennung ist nicht deklariert, das dürfte wohl ein Integer sein (Short oder Integer)
    Messdatum wenn das mit Now ermittelt wurde, ist es ggf. ein Double. Die Vorkommastellen sind das Datum, die Nachkommastellen die Zeit.
    Den Rest bekommst Du so hin.
    Arbeite in jedem Falle mit Option Strict On :!:
    Wenn Du das Format dann lesen kannst, arbeite mit einem BinaryReader!
    =====
    Du musst Dir die DAtei unbedingt mit einem Hex-Viewer ansehen, damit Du verfolgen kannst, was da losgeht.
    Das Auslesen von Basic-Strings und der Strukturen hab ich mal implementiert.
    Du musst natürlich noch das Drumherum basteln.
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.IO
    2. Imports System.Text
    3. Public Class Form1
    4. Structure Meßkoordinaten
    5. Public Punkt As Integer
    6. Public X_Wert As Double
    7. Public Y_Wert As Double
    8. Public Z_Wert As Double
    9. End Structure
    10. Structure Durchmesserwerte
    11. Public Wert1 As Single
    12. Public Wert2 As Single
    13. Public Wert3 As Single
    14. Public Wert4 As Single
    15. Public Wert5 As Single
    16. End Structure
    17. Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    18. Dim value As Short
    19. Dim Dateikennung As String
    20. Dim Messdatum As Double
    21. Dim bytes() As Byte
    22. Dim koord As Meßkoordinaten
    23. Dim durchm As Durchmesserwerte
    24. Dim path = "F:\Binärdatei\MESS_H02\MESS_H02.PSC"
    25. Dim str = New IO.FileStream(path, FileMode.Open)
    26. Using br = New BinaryReader(str)
    27. value = br.ReadInt16()
    28. bytes = br.ReadBytes(value)
    29. Messdatum = br.ReadDouble()
    30. koord = ReadKoordinaten(br)
    31. durchm = ReadDurchmesser(br)
    32. End Using
    33. Dateikennung = Encoding.Default.GetString(bytes)
    34. Stop
    35. End Sub
    36. Private Function ReadKoordinaten(ByVal br As BinaryReader) As Meßkoordinaten
    37. Dim koord As Meßkoordinaten
    38. koord.Punkt = br.ReadInt32()
    39. koord.X_Wert = br.ReadDouble()
    40. koord.Y_Wert = br.ReadDouble()
    41. koord.Z_Wert = br.ReadDouble()
    42. Return koord
    43. End Function
    44. Private Function ReadDurchmesser(ByVal br As BinaryReader) As Durchmesserwerte
    45. Dim durchm As Durchmesserwerte
    46. durchm.Wert1 = br.ReadSingle()
    47. durchm.Wert2 = br.ReadSingle()
    48. durchm.Wert3 = br.ReadSingle()
    49. durchm.Wert4 = br.ReadSingle()
    50. durchm.Wert4 = br.ReadSingle()
    51. End Function
    52. End Class

    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „RodFromGermany“ ()

    Visual Basic-Quellcode

    1. Type Meßkoordinaten
    2. Punkt As Integer -----> Short oder Int16
    3. X_Wert As Double
    4. Y_Wert As Double
    5. Z_Wert As Double
    6. End Type


    Ein VB.net Integer entspricht einem VB6 Long
    Ein VB6 Integer muss bei VB.net als Short oder Int16 deklariert werden

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Eierlein“ ()

    sorry, dass ich mich so lange nicht gemeldet hab. jetzt bin ich aber wieder da...

    @RodFromGermany: hast du es so ausgelesen bekommen? ?(

    RodFromGermany schrieb:


    VB.NET-Quellcode

    1. Dim path = "F:\Binärdatei\MESS_H02\MESS_H02.PSC"
    2. Dim str = New IO.FileStream(path, FileMode.Open)
    3. Using br = New BinaryReader(str)
    4. value = br.ReadInt16()
    5. bytes = br.ReadBytes(value)
    6. Messdatum = br.ReadDouble()
    7. koord = ReadKoordinaten(br)
    8. durchm = ReadDurchmesser(br)
    9. End Using


    Messdatum wenn das mit Now ermittelt wurde, ist es ggf. ein Double. Die Vorkommastellen sind das Datum, die Nachkommastellen die Zeit.

    Das Messdatum wird nicht mit Now ermittelt, sondern händisch eingegeben. Es ist nur ein Datum, als String deklariert.

    tina83 schrieb:

    hast du es so ausgelesen bekommen?
    Ja.
    Ich hab das am "lebenden Objekt" entwickelt.
    Das Datum war allerdings nicht dabei.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    und alles andere ist dann da? nicht schlecht :thumbup:
    kannst du mir noch einen Tipp geben, damit es bei mir auch klappt? Weil ehrlich gesagt versteh ich deinen Weg nicht so ganz.
    Wozu brauch ich diese Schritte?

    VB.NET-Quellcode

    1. value = br.ReadInt16()
    2. bytes = br.ReadBytes(value)
    3. Messdatum = br.ReadString()

    Ich dachte es ginge anders (funktioniert aber nicht):

    VB.NET-Quellcode

    1. Dateikennung = br.ReadString()
    2. Messdatum = br.ReadString()
    3. Kennwort = br.ReadString()
    4. 'usw.


    *Vollzitat entfernt* ~NoFear23m

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Nofear23m“ ()

    tina83 schrieb:

    versteh ich deinen Weg nicht so ganz.
    Ich hab zwei Strukturen, deren Datentypen Du anpassen musst.
    Das Auslesen der Strukturen hab ich Dir implementiert, hier musst Du die korrekten Read-Befehle einsetzen.
    Das Einlesen eines VB6-Strings hab ich Dir auch gezeigt.
    Im Gesamtablauf musst Du in der Schleife

    VB.NET-Quellcode

    1. Using br = New BinaryReader(str)
    2. ' hier
    3. End Using
    einfach die Read-Befehle für die Einzelwerte (Strings, Strukturen, was auch immer) in der richtigen Reihenfolge aneinanderhängen.
    Feddich. ;)
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    einfach die Read-Befehle für die Einzelwerte (Strings, Strukturen, was auch immer) in der richtigen Reihenfolge aneinanderhängen.

    Du übersiehst dabei, das die Datensatzlänge der vorhandenen Random-Datei 128 Bytes beträgt.
    (Unnötigerweise 128 Bytes weil keine Länge angegeben wurde).

    Das Einlesen eines VB6-Strings hab ich Dir auch gezeigt.

    Ein String in einer Random-Datei wird so gespeichert:
    Stringlänge ( Short / INT16) --- String --- der Rest der 128 Bytes Chr(0)
    das ist der entscheidende Punkt:

    Eierlein schrieb:

    Du übersiehst dabei, das die Datensatzlänge der vorhandenen Random-Datei 128 Bytes beträgt.


    Einfach nur Readstring funktioniert nicht. Wenn ich jedoch immer 128 Bytes auslese, sieht die Sache schon viel besser aus. Dann ist der Inhalt da, aber leider auch sehr viele VBNullChar, VBVerticalTab, VBLf, VBCr, usw. und der String ist in Anführungszeichen, z.B. "Koordinaten".
    jetzt läufts. Das eigentlich einzige Problem war die Deklarierung von Public Punkt As Short. Es wird zwar in Integer in VB6 gespeichert, muss in VB.NET als Short deklariert werden.
    Danke Eierlein :thumbup:

    Aber mich würde es schon noch interessieren wie ich am geschicktesten den Readstring-Befehl anwenden kann, ohne die VBNullChar, usw. und die "" ?(
    Wie ein String gespeichert wir, hatte ich schon geschrieben:
    Ein String in einer Random-Datei wird so gespeichert:
    Stringlänge (INT16) - String - der Rest der 128 Bytes Chr(0)


    String auslesen (PseudoCode)

    Quellcode

    1. Dim z as integer = 0
    2. Datei im Binärmodus öffnen (Zeiger steht auf 0)
    3. Stringlänge lesen --> Readint16 (Zeiger steht auf 2)
    4. String lesen, Anzahl Bytes laut Stringlänge
    5. z = z + 1
    6. Dateizeiger mittels Seek auf 128 setzen ---> .Seek(z * 128, SeekOrigin.Begin)
    7. Nächsten String lesen
    8. z = z + 1
    9. Dateizeiger mittels Seek auf 256 setzen ---> .Seek(z * 128, SeekOrigin.Begin)
    10. ...
    11. z = z + 1
    12. ---> .Seek(z * 128, SeekOrigin.Begin)
    13. ...
    14. Meßkoordinaten lesen (26 Bytes)
    15. Entweder die Structure oder die einzelnen Werte
    16. ReadInt16
    17. ReadDouble
    18. ReadDouble
    19. ReadDouble
    20. z = z + 1
    21. ---> .Seek(z * 128, SeekOrigin.Begin)
    22. ...
    23. usw.



    Oder Einfach Bei der Random Version bleiben.
    Da würde ich eine Prozedur machen, die genau einen String ausliest, wie mit den Strukturen.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!