Struct in Byte Array Serialisieren

  • C#
  • .NET (FX) 4.0

Es gibt 16 Antworten in diesem Thema. Der letzte Beitrag () ist von MrSchabernack.

    Struct in Byte Array Serialisieren

    Hallo,

    möchte ein struct wie der Titel schon sagt in ein Array mit den Datentyp Byte Serialisieren. Hat jemand einen Vorschlag wie man das machen könnte da mir die Beispiele im Internet nicht wirklich helfen.

    Mein Struct:

    Quellcode

    1. [Serializable]
    2. public struct TestStruct
    3. {
    4. public byte bFeld1;
    5. public Int16 iFeld2;
    6. public Int32 iFeld3;
    7. }


    Habe schon öfters etwas über den BinaryFormatter gelesen, müsste ich diesen evtl. verwenden ?

    Grüße MrSchabernack
    Richtig: Verweis auf System.Runtime.Serialization(und evtl. auch auf System.Runtime.Serialization.Formatters.Binary) setzen und entsprechende Namespaces importieren. Dann den BinaryFormatter initialisieren und mit .Serialize(Obj) und .Deserialize(Stream) arbeiten.
    @Highlav hättest du evtl ein Code Beispiel? Steh grad aufn Schlauch.

    Mein Code zum Serialisieren:

    Quellcode

    1. public void Serialize()
    2. {
    3. byte[] bArray;
    4. BinaryFormatter formatter = new BinaryFormatter();
    5. formatter.Serialize(bArray, TestStruct);
    6. }


    funktioniert leider nicht.
    Sorry, VS habe ich gerade nicht und Zeit zu wenig. Aber ich kann's ja mal mit meinem gebrochenen Blind-C# versuchen: ;)

    C#-Quellcode

    1. Var MyStruct = New MyStructure;
    2. Var BinF = New BinaryFormatter();
    3. Byte() Buffer = Null; //Oder Nothing??
    4. using (Var MS = New MemoryStream())
    5. {
    6. BinF.Serialize(MS, MyStruct);
    7. Buffer = MS.GetBuffer();
    8. }

    Danke, hab es grade noch selbst hin bekommen :D

    Mein Code ist aber ähnlich

    Quellcode

    1. public void Serialize()
    2. {
    3. TestStruct ts = new TestStruct();
    4. MemoryStream ms = new MemoryStream();
    5. BinaryFormatter formatter = new BinaryFormatter();
    6. formatter.Serialize(ms, ts);
    7. byte[] bArray = ms.ToArray();
    8. }
    ToArray? Kenne ich nicht - Ich nutze immer GetBuffer. ?( Und du gibst den MemoryStream nicht frei -> .Dispose aufrufen, oder mit einem using-Statement automatisieren.
    Was willst du eigentlich mit dem serialisierten Objekt machen, wenn cih fragen darf?

    EDIT: Oh. nafets war schneller...
    @ErfinderDesRades dies bezüglich hab ich mich noch nicht schlau gemacht.

    Habe aber grad noch ein Problem, nach der Serialisierung müssten doch in meinen Array wo der MemoryStream dann die Werte rein gibt, ausschließlich 1 und 0en sein, oder nicht? in meinem Array stehen aber recht komische Zahlen.

    Code:

    Quellcode

    1. public void test()
    2. {
    3. BinaryFormatter bf = new BinaryFormatter();
    4. byte[] bAr;
    5. using (MemoryStream ms = new MemoryStream())
    6. {
    7. bf.Serialize(ms, ts);
    8. bAr = ms.GetBuffer();
    9. }
    10. foreach (byte bx in bAr)
    11. lstB.Items.Add(bx.ToString());
    12. }


    Werte in meinem Array:
    Spoiler anzeigen

    Quellcode

    1. 0
    2. 1
    3. 0
    4. 0
    5. 0
    6. 255
    7. 255
    8. 255
    9. 255
    10. 1
    11. 0
    12. 0
    13. 0
    14. 0
    15. 0
    16. 0
    17. 0
    18. 12
    19. 2
    20. 0
    21. 0
    22. 0
    23. 73
    24. 85
    25. 68
    26. 80
    27. 84
    28. 101
    29. 115
    30. 116
    31. 84
    32. 111
    33. 111
    34. 108
    35. 95
    36. 67
    37. 108
    38. 105
    39. 101
    40. 110
    41. 116
    42. 44
    43. 32
    44. 86
    45. 101
    46. 114
    47. 115
    48. 105
    49. 111
    50. 110
    51. 61
    52. und noch viel mehr

    Byte != Bit
    Bytes haben je 2^8(=256) Möglichkeiten. Sie bestehen aus 8 Bits, welche wiederum nur 1 oder 0 annehmen können. 2^8 != 2
    Das ist schon richtig so. ;)
    So jetzt steck ich natürlich bei der Deserialisierung fest.
    mein code:

    Quellcode

    1. BinaryFormatter bf = new BinaryFormatter();
    2. using (MemoryStream ms = new MemoryStream(bdata))
    3. {
    4. //das mit der Messagebox ist natürlich nur ein Test
    5. MessageBox.Show(bf.Deserialize(ms).ToString());
    6. }


    bdata ist ein Array aus Bytes, darin sind die Daten enthalten welche ich per Udp empfangen habe. Nur bringt er mir jetzt folgende Fehlermeldung.

    MrSchabernack schrieb:

    folgende Fehlermeldung
    musst Du lesen, verstehen und umsetzen.
    Was ist UDPTestTool_Client :?:
    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!
    Versuch mal:

    C#-Quellcode

    1. BinaryFormatter bf = new BinaryFormatter();
    2. using (MemoryStream ms = new MemoryStream(bdata))
    3. {
    4. //das mit der Messagebox ist natürlich nur ein Test
    5. Var MyStruct = (MyStructure)bf.Deserialize(ms));
    6. MessageBox.Show(MyStruct.ToString());
    7. }

    Kann es sein, dass dein Programm nicht weiss, was für ein Typ es ist? Falls du mehrere Typen hast, die du versenden willst, kannst du Header mitliefern. Nach dem deserialisieren kannst du über den ausgelesenen Header den Typ bestimmen...
    Und: Wie EDR schon fragte: Funktioniert die Übertragung über einen Stream? Also über Sockets? Wenn ja, kannst du dir den Krimskrams mit dem MemoryStream sparen und gleich den Networkstream zum Serialisieren/Deserialisieren verwenden.

    ErfinderDesRades schrieb:

    hat man bei udp nicht auch einen Stream?
    AFAIK nein, da UDP verbindugnslos is.

    Wenn es auf Performance ankommt, würde ich da keinen BinaryFormatter verwenden, da dieser noch diverse Metainformationen mitserialisiert.

    Du könntest es also auch so versuchen:

    C#-Quellcode

    1. byte[] GetBytes<T>(T str)
    2. where T : struct
    3. {
    4. int size = Marshal.SizeOf(typeof(T)); // größe des Structs holen (in bytes)
    5. byte[] arr = new byte[size]; // Bytearray mit der größe allokieren
    6. IntPtr ptr = Marshal.AllocHGlobal(size); // Speicher im Heap allokieren
    7. Marshal.StructureToPtr(str, ptr, true); // Struct-Instanz nach Heap kopieren
    8. Marshal.Copy(ptr, arr, 0, size); // Aus dem Head in das Bytearray kopieren
    9. Marshal.FreeHGlobal(ptr); // Speicher im Heap wieder freigeben
    10. return arr; // Fertiges Byte-Array zurückgeben
    11. }
    12. T FromBytes<T>(byte[] arr)
    13. where T : struct
    14. {
    15. int size = Marshal.SizeOf(typeof(T)); // größe des Structs holen (in bytes)
    16. IntPtr ptr = Marshal.AllocHGlobal(size); // Speicher im Heap allokieren
    17. Marshal.Copy(arr, 0, ptr, size); // Bytes nach Heap kopieren
    18. T str;
    19. Marshal.PtrToStructure<T>(ptr, str); // Struct-Instanz aus Heap-Pointer erstellen
    20. Marshal.FreeHGlobal(ptr); // Heapspeicher wieder freigeben
    21. return str; // Struct-Instanz zurückgeben
    22. }

    Habe es nicht getestet und es geht sicherlich auch mit unsafe, falls es da wieder solche Fetischisten gibt. Man sollte auch über ein Try-Catch nachdenken, da bei einer Exception der allokierte Speicher im Heap eventuell nicht wieder freigegeben wird, was dann zu einem Memoryleak führt.

    So bekommst du aus dem TestStruct auch nur ein Byte-Array, was die Größe von sizeof(TestStruct) hat. Dabei verlierst du natürlich die Vorteile, die ein BinaryFormatter hat.
    Von meinem iPhone gesendet

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „nikeee13“ ()