Daten eines Structure-Arrays serialisieren?

  • VB.NET

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

    Daten eines Structure-Arrays serialisieren?

    Hallo Leute!

    Ich stehe vor der Herausforderung eine Datenstruktrur als einzelnen Stream (String) über TCP-Socket zu versenden.

    Beispiel:

    VB.NET-Quellcode

    1. Structure TestStruct
    2. Dim ID as integer
    3. Dim Name as String
    4. Dim Status as Boolean
    5. ...
    6. End Structure
    7. Dim EinzelnerDatensatz as TestStruct
    8. Dim MehrfacherDatensatz(100) as TestStruct


    Nun möchte ich

    a) Den kompletten Inhalt von "EinzelnerDatensatz" serialisieren
    b) Den kompletten Inhalt der Mehrdimensionalen Struktur "MehrfacherDatensatz" serialisieren

    Also Daten auf einem Gerät in einen "sendbaren" String verwandeln und am anderen Gerät die Daten wieder in die Structure "schreiben".

    Geht auch ein mehrdimensionales Feld zu serializieren (und wenn ja wie) oder muss ich mir da selbst per Schleife einen "String" zur Übergabe "basteln"?

    LG Roland
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at
    Hi
    warum muss es ein String sein? TCP erwartet Bytes, Structures und alle sonstigen Daten sind Bytes, also warum nicht zu solchen serialisieren oder Serialisierung nur als optionale Codierung der Daten verwenden?
    Interessant in diesem Zusammenhang könnte auch der Artikel von mir sein:
    [C#] Versenden von Objekten über TCP

    Gruß
    ~blaze~
    String wäre praktisch, da ich diese Daten mit anderen Informationen zuerst in einen String verpacke und den dann in Bytes umwandle. Im Beispielcode sollte dort <xml irgendwas>.....</xml> steht die Daten der Structur hin. Ob das im Format <xml ... oder "00110010010" ist, ist eigentlich egal. Als String wäre es einfach zu handhaben.

    Die Daten sollen in diesem Format gesendet werden: (hinter dem Tag "Data" steht dann die Struktur in einem String):

    VB.NET-Quellcode

    1. TCPSendeString="#DATARETURN|USER=22|TABLE=8|DATA=<xml irgendwas>.....</xml>|#"
    2. Dim msg As [Byte]() = System.Text.Encoding.ASCII.GetBytes(TCPSendeString)
    3. stream.Write(msg, 0, msg.Length)



    Wenn es einfacher ist das ganze in bytes umzuwandeln: wäre folgendes möglich:?

    VB.NET-Quellcode

    1. Dim ErsterTeil As [Byte]() = System.Text.Encoding.ASCII.GetBytes("#DATARETURN|USER=22|TABLE=8|DATA=")
    2. ZweiterTeil=xxxx 'hier die Structure in bytes einfügen
    3. Dim DritterTeil As [Byte]() = System.Text.Encoding.ASCII.GetBytes("|#" )
    4. 'hier die drei byteinformationen aneinanderreihen und dann senden


    Danke für den Link, aber mit C kenne ich mich leider überhaupt nicht aus.

    LG Roland
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at
    Die Sachen vorher lassen sich aber eigentlich auch leichter Binär darstellen, sind ja bloß zwei Zahlen und eine Kennung (die man auch als Zahl senden könnte).
    Bei der Binären Serialisierung hast du halt den Vorteil, dass du einfach das Serializable-Attrubut auf die Klasse anwenden brauchst und der Rest wird dir praktisch komplett abgenommen.

    Das in dem Link ist übriges kein C, sondern C#, also eigentlich genau das selbe wie VB.
    Ich glaube ich habe einen Lösungsansatz gefunden:


    VB.NET-Quellcode

    1. <Serializable()> _
    2. Public Structure BedienerStructure
    3. Dim Benutzer_ID As Integer
    4. Dim Name As String
    5. Dim BildschirmName As String
    6. Dim AnmeldeCode1 As String
    7. .....
    8. Dim IstNurManager As Boolean
    9. Dim LetzteAenderung As DateTime
    10. End Structure
    11. Public Bediener(501) As BedienerStructure


    Nur den ersten Datensatz Bediener(1) :

    VB.NET-Quellcode

    1. Dim bytes(1024 * 1024) As [Byte]
    2. bytes = SerializeObject(Bediener(1))
    3. MsgBox(bytes.Length.ToString) 'gibt die Länge der Bytes aus
    4. Dim DatenString as String =Convert.ToBase64String(bytes) 'gibt die Bytes als String aus
    5. TCPSendeString="#DATARETURN|USER=22|TABLE=8|DATA="+ DatenString +"|#"


    Die komplette Structur Bediener :

    VB.NET-Quellcode

    1. Dim bytes(1024 * 1024) As [Byte]
    2. bytes = SerializeObject(Bediener)
    3. MsgBox(bytes.Length.ToString) 'gibt die Länge der Bytes aus
    4. Dim DatenString as String =Convert.ToBase64String(bytes) 'gibt die Bytes als String aus
    5. TCPSendeString="#DATARETURN|USER=22|TABLE=8|DATA="+ DatenString +"|#"


    Das wichtigste hätte ich glatt vergessen:

    VB.NET-Quellcode

    1. Public Function SerializeObject(ByVal What As Object) As Byte()
    2. Dim MemStream As New MemoryStream
    3. Dim BinWriter As New BinaryWriter(MemStream)
    4. Dim BinFormatter As New BinaryFormatter
    5. BinFormatter.Serialize(BinWriter.BaseStream, What)
    6. BinWriter.Close()
    7. Return MemStream.ToArray
    8. End Function


    Und zurück gehts dann natürlich auch wieder:

    VB.NET-Quellcode

    1. Public Function DeSerializeObject(ByVal What() As Byte) As Object
    2. Dim MemStream As New MemoryStream(What)
    3. Dim BinFormatter As New BinaryFormatter
    4. Dim RetObj As Object = BinFormatter.Deserialize(MemStream)
    5. MemStream.Close()
    6. Return RetObj
    7. End Function


    Hab testweise probiert Bediener(1) mit dieser Methode in bytes>string>bytes nach Bediener(10) zu kopieren (nur Testweise).
    Hat funktioniert.
    Da das ursprünglich geplante direkte Auslesen von Accessdateien von der Kasse via PDA nicht funktioniert und ich über dieses "geile" TCP gestolpert bin (mit dem ich zuvor noch nie etwas zu tun hatte), werde ich nun die komplette Kommunikation über TCP abwickeln und nicht gemischt mit XML-Dateien die über das Dateisystem gelesen werden.
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at

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

    Hallo Leute,

    dieser Thread ist schon etwas älter und ich dachte damals die Lösung meiner Aufgabe bereits gefunden zu haben. Leider ist dem nicht so.

    Das Problem: auf dem .NET Compact Framework gibt es keinen BinaryFormatter. Somit kann ich die binären Dateien nicht wieder in Structure zurückverwandlen.

    Ursprünglich dachte ich an das (DeSerializeObject und SerializeObject wurden oben schon gepostet):

    VB.NET-Quellcode

    1. 'hin
    2. Dim bytes(2048 * 2048) As [Byte]
    3. bytes = SerializeObject(PDABediener)
    4. XMLSendString = Convert.ToBase64String(bytes) 'gibt die Bytes als String aus
    5. 'Zurück
    6. Dim bytes(2048 * 2048) As [Byte]
    7. bytes = Convert.FromBase64String(Empfangsdaten.DATA)
    8. PDABediener = DeSerializeObject(bytes)


    Das kann ich mir nun abschminken, da es im .NET Compact Framework keinen BinaryFormatter gibt.

    Bei den paar Daten könnte ich die Infos auch mit Trennzeichen in einen String verpacken und übermitteln. Das wäre nicht unüberwindbar.

    Wie aber kann ich dann Bilder über TCP-IP übertragen?
    Also eine Image-Datei die im Speicher auf dem Rechner vorliegt auf den PDA übertragen und dort in einer Picturebox anzeigen.?

    LG Roland
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at
    Du kannst ein Image-Objekt in einen Stream rein abspeichern. Da könntest du dann deinen TCP-Stream über geben oder einen MemoryStream, aus welchem du dann die Bytes ausliehst.
    Gibt es auch irgend eine Möglichkeit per TCP-IP komplette Dateien von einem Windows Rechner auf den Pocket-PC zu übertragen und dort einfach als Datei zu speichern. Diese kann dann ja von der .NET Compact Framework anwendung geladen werden. Wenn das irgendwie einfacher ginge ...

    MemoryStream, aus welchem du dann die Bytes ausliehst.
    Gerade das geht ja nicht, da es keinen BinaryFormatter in .NET CF gibt!!
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at

    dive26 schrieb:

    komplette Dateien
    musst Du ganz oder blockweise (je nach Größe) als Bytearray senden und empfangen.
    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!
    Danke Rod, habe ich befürchtet.

    Ich bin nun auch mit der Übertragung einer Structure einen Schritt weiter, hoffe aber dass mir das .NET CF keinen Strich durch die Rechnung macht.

    Ich kann zumindest nun eine Struktur in einen XML-String umwandeln und per TCP an den PDA senden.
    Dort liegt mir nun auch der exakte XML-String vor.

    VB.NET-Quellcode

    1. Dim MemStream As New MemoryStream
    2. 'PDABediener ist eine Structure
    3. SerializeXml(MemStream, PDABediener)
    4. XMLSendString = Encoding.ASCII.GetString(MemStream.ToArray())


    Wie kann ich nun auf der .NET Compact Framework Seite diesen Vorgang umkehren und diesen XML-String wieder in einen MemoryStream zurückverwandeln und dann mit DeserializeXML in die Struktur PDABediener zurückschreiben ?

    Ich muss jetzt mal was essen gehen, bin total wuschi im Kopf.

    LG Roland
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at

    dive26 schrieb:

    Gerade das geht ja nicht, da es keinen BinaryFormatter in .NET CF gibt!!

    Laut MSDN gibt es den MemoryStream im .NET Compact Framework. Ich meinte sowas:

    Quellcode

    1. Using MemoryStream ms = New MemoryStream()
    2. MyImage.Save(ms)
    3. Dim bytes as Byte() = ms.ToArray()
    4. Ende Using

    Oder halt so:

    Quellcode

    1. MyImage.Save(MyTcpStream)

    Das hat doch alles nichts mit dem BinaryFormatter zu tun und müsste daher gehen, oder?
    Das eine ist ein Bild zu übertragen (danke für den Tipp) und das andere ist eine komplette Structure zu übertragen (daran scheitere ich zur Zeit).


    Das ist die Structur, die auf Host (PC) und Client (PDA) zur Verfügung steht

    VB.NET-Quellcode

    1. <Serializable()> _
    2. Public Structure BedienerStructure
    3. Dim Benutzer_ID As Integer
    4. Dim Name As String
    5. Dim AnmeldeCode1 As String
    6. Dim AnmeldeCode2 As String
    7. Dim AnmeldeCode3 As String
    8. Dim BenutzerBild_memo As String 'serialisiertes Bild
    9. Dim Finger1_memo As String 'serialisierte biometrische Daten
    10. Dim Finger2_memo As String 'serialisierte biometrische Daten
    11. Dim Finger3_memo As String 'serialisierte biometrische Daten
    12. Dim gesperrt As Boolean
    13. Dim ManagerRecht As Boolean
    14. Dim StornoRecht As Boolean
    15. Dim PreisAenderungsRecht As Boolean
    16. Dim TagesAbschlussRecht As Boolean
    17. Dim MonatsAbschlussRecht As Boolean
    18. Dim BerichteRecht As Boolean
    19. Dim LagerzugangsRecht As Boolean
    20. Dim TischrueckholungsRecht As Boolean
    21. Dim ArtikelAenderungsRecht As Boolean
    22. Dim BenutzerSetupRecht As Boolean
    23. Dim UmsatzanzeigeRecht As Boolean
    24. Dim AlleTischnummernRecht As Boolean
    25. Dim Sonderberechtigung1 As Boolean
    26. Dim Sonderberechtigung2 As Boolean
    27. Dim Sonderberechtigung3 As Boolean
    28. Dim Revierzwang As Boolean
    29. Dim RevierzwangVonTisch As Integer
    30. Dim RevierzwangBisTisch As Integer
    31. Dim SofortstornoVerbieten As Boolean
    32. Dim ArbeitsZeitAngemeldet As Boolean
    33. Dim IstNurManager As Boolean
    34. Dim LetzteAenderung As DateTime
    35. Dim Provision As Double
    36. End Structure
    37. Public PDABediener As BedienerStructure


    Folgender Code bringt dann das im Anhang zu sehende Ergebnis. Dieser XML-String liegt mir nun auch schon am PDA vor. Dort sollen nun die XML-Informationen wieder in die Structure kopiert werden. Daran scheitere ich gerade.

    VB.NET-Quellcode

    1. Dim MemStream As New MemoryStream
    2. SerializeXml(MemStream, PDABediener)
    3. XMLSendString = Encoding.ASCII.GetString(MemStream.ToArray())
    4. MsgBox(XMLSendString)
    5. ''' <summary>
    6. ''' Extension zur XML Serialisierung und Speicherung von komplexen Objekt-Structuren in eine Datei
    7. ''' </summary>
    8. ''' <param name="strm">FileStream</param>
    9. ''' <param name="obj">Objekt</param>
    10. ''' <remarks></remarks>
    11. <Extension()> _
    12. Public Sub SerializeXml(ByVal strm As Stream, ByVal obj As Object)
    13. Call (New XmlSerializer(obj.GetType)).Serialize(strm, obj)
    14. End Sub
    Bilder
    • Bedienerstructure.jpg

      277,05 kB, 489×694, 170 mal angesehen
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at

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

    Ich weiß nicht, ob es möglich ist, System.Reflection zu verwenden - wenn ja, ließe sich damit auf jeden Fall eine (generische) Möglichkeit bauen, mit welcher man Structures serialisieren kann.
    Ich glaube ich bin nah an der Lösung dran, die auch auf .NET CF funktioni:

    VB.NET-Quellcode

    1. Dim Ptr As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(PDABediener))
    2. Dim ByteArray(Marshal.SizeOf(PDABediener) - 1) As Byte
    3. Marshal.StructureToPtr(PDABediener, Ptr, False)
    4. Marshal.Copy(Ptr, ByteArray, 0, Marshal.SizeOf(PDABediener))
    5. Marshal.FreeHGlobal(Ptr)
    6. 'hier liegen die Daten in ByteArray und müssen nur in einen String umgewandelt werden
    7. '???????
    8. 'hier liegen die Daten in einem String und müssen nur noch in ein Bytarray zurückverwandelt werden
    9. '???????
    10. 'Und wieder zurück
    11. Dim Ptr1 As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(PDABediener))
    12. Dim ByteArray1(Marshal.SizeOf(PDABediener) - 1) As Byte
    13. Marshal.StructureToPtr(PDABediener, Ptr1, False)
    14. Marshal.Copy(Ptr1, ByteArray1, 0, Marshal.SizeOf(PDABediener))
    15. Dim Ptr2 As IntPtr = Marshal.AllocHGlobal(ByteArray1.Length)
    16. Marshal.Copy(ByteArray1, 0, Ptr2, ByteArray1.Length)
    17. Dim PDABediener2 As New BedienerStructure
    18. PDABediener2 = DirectCast(Marshal.PtrToStructure(Ptr2, GetType(BedienerStructure)), BedienerStructure)
    19. PDABediener = PDABediener2
    20. MsgBox(PDABediener.Name)
    21. Marshal.FreeHGlobal(Ptr)


    Ich brauche nun nur noch eine Lösung wie ich das vorhandene ByteArray in einen String umwandeln kann und auch wieder zurück.
    Ist sicher einfach, ich komme nur grad nicht dahinter.

    LG Roland
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at

    dive26 schrieb:

    in einen String umwandeln
    So:

    VB.NET-Quellcode

    1. Dim by() As Byte = {51, 52, 53, 54, 55, 56}
    2. Dim txt = System.Text.Encoding.Default.GetString(by)
    3. MessageBox.Show(txt)
    4. Dim bb() As Byte = System.Text.Encoding.Default.GetBytes(txt)

    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!
    Danke Rod,
    also eh so einfach ;) .

    leider habe ich gerade bemerkt, dass

    VB.NET-Quellcode

    1. Marshal.StructureToPtr(PDABediener, Ptr1, False)
    auf .NET Compact Framework einen undefinierten Ausnahmefehler bringt.

    Muss also wieder eine weitere (andere) Lösung suchen.

    Irgendwie muss es doch möglich sein den Inhalt einer Structure in String zu wandeln und auf CF wieder von String in Structure zurückzuschreien. Ich habe schon so viele Lösungsansätze versucht, immer macht mir CF einen Strich durch die Rechnung weil entsprechende Funktionen dort einfach nicht vorhanden sind.

    LG Roland
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at

    dive26 schrieb:

    Ausnahmefehler
    Ich hab Deinen Code nicht vollständig durchgesehen, vielleicht gugst Du mal hier ob der korrekten Marshal-Verwendung.
    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!