Strukturen schreiben und einlesen

  • VB.NET

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

    Strukturen schreiben und einlesen

    Hi,

    Ich möchte die folgenden Daten auf einen File schreiben und später diesen File exakt in genau der gleichen Weise in die Variablen wieder einlesen.

    Die Daten sollen zwischendurch in keiner Weise konvertiert werden.

    VB.NET-Quellcode

    1. 'Logging and Recovery
    2. Public log As String
    3. Public rba As Integer
    4. Public lorba As Integer
    5. Public hirba As Integer
    6. Public rba_autofill As Integer
    7. Public rba_autofill2 As Integer
    8. Public rba_savepoint(MAXSAVEPOINTS + 1) As Integer
    9. Public Savepoint_Number As Integer


    Die Variable "log" hat bei jedem Aufruf möglicherweise andere Längen.

    Ich erinnere mich dunkel an eine "struct" Anweisung ... aber die gibt es jetzt in VB 2010 wohl nicht mehr.

    LG
    Peter
    Doch, Structures gibt es immer noch.

    VB.NET-Quellcode

    1. Structure Test
    2. Public log As String
    3. Public rba As Integer
    4. Public lorba As Integer
    5. Public hirba As Integer
    6. Public rba_autofill As Integer
    7. Public rba_autofill2 As Integer
    8. Public rba_savepoint(MAXSAVEPOINTS + 1) As Integer
    9. Public Savepoint_Number As Integer
    10. End Structure


    Wenn du nix spezielles mit dem gespeicehrten vor hast, kannst du dafür einen BinaryFormatter (binäre serialisierung) oder einen XmlSerializer (XML-Serialisierung) verwenden. Gibt auch noch ein paar andere.
    Von meinem iPhone gesendet

    RushDen schrieb:

    Arrays, die als Strukturmember deklariert sind, können nicht mit einer vorgegebenen Größe definiert werden.

    Stimmt. Das geht nicht. Man darf bei einem Struct keine Array-Größe mit angeben. Ich hab da seinfach nur kopiert und nicht auf den Inhalt geachtet.
    Von meinem iPhone gesendet

    VB.NET-Quellcode

    1. Private Sub DeSerialize(Of t)(ByVal path As String)
    2. Dim formatter As New BinaryFormatter
    3. Using Stream As FileStream = File.OpenRead(path)
    4. Dim reloadTest As t = DirectCast(formatter.Deserialize(Stream), t)
    5. End Using
    6. End Sub
    7. Private Sub Serialize(Of t)(ByVal obj As t, ByVal path As String)
    8. Dim formatter As New BinaryFormatter
    9. Using Stream As FileStream = File.Create(path)
    10. formatter.Serialize(Stream, obj)
    11. End Using
    12. End Sub


    (Binär)

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

    Mh ... also diese beiden Prozeduren sollen wohl irgendwie die Variablen "serialisieren" und dann wieder "deserialisieren".

    t ist die Liste der Variablen?

    path ist der Pfad auf den geschrieben und von dem dann später wieder gelesen werden soll?

    Dann müssten die Prozeduren in der Reihenfolge "Serialize" und dann "DeSerialize" aufgerufen werden?

    Also irgendwie habe ich keinen Plan, wie ich das umsetzen soll!

    LG
    Peter
    umh also Serialize ist halt die Prozedur um das Objekt in eine Datei reinzuschreiben im folgendenen Pfad (Datei wird erstellt) und DeSerialize lädt die gespeicherte Struktur wieder in die Variable rein.
    t ist der Datentyp der wird beim Serialisieren aus dem angegebenen Objekt herausgeschlossen (weil dieser auch t ist) und beim Deserializieren muss dieser mitangegeben werden, anschliessend wird das eingelesene Objekt in den Typ gecastet und in die Variable gepackt.
    Am Ende wird das gelesene Objekt (also mit den Eigenschaften etc des gespeicherten Objekts) in die Variable reloadTest geladen.


    Ahso du musst die Structure noch mit <Serializable> kennzeichnen:

    VB.NET-Quellcode

    1. <Serializable>
    2. Public Structure Test
    3. '...

    und Imports:

    VB.NET-Quellcode

    1. Imports System.Runtime.Serialization.Formatters.Binary
    Benutze doch ein DataSet. Da brauchst du nur .WriteXML und .ReadXML zu schreiben und der Rest geht von 'alleine'. Ansonsten sehe ich keinen Grund hier eine Structure zu benuzten - eine Klasse macht es auch. Structures sollte man nur benutzen, wenn man zu 130% weiß, was man tut.
    Bei einer Structure (oder Klasse) kann man btw per Attribut und Konstruktor feste Stringlängen und Arraygrößen (und sehr viel anders) festlegen. Das sind meiner Meinung nach aber Möglichkeiten, die man nur bei Sonderfällen (dann, wenn es wirklich nicht anders geht) nutzen sollte.
    Entschuldigt, dass ich den alten Beitrag wieder ausgrabe.
    Jedoch ist dieser wieder aktuell und ich habe ein kleines Problem das ich lösen muss.

    Ich speichere (seit 2014) Daten von Structures mit dem Binary-Writer ab.
    In den Dateien befindet sich auch der Stamm-Namespace.
    In der bisher verwendeten Software lautet dieser "BONitFlexX".

    Nun bin ich dabei die Software zu überarbeiten (neue Version) und habe dieser einen neuen Stammnamespace"BONitFlexXPRO" gegeben.
    Wenn ich nun die "alten" Dateien wieder mit dem serializer einlesen möchte, dann gibt es eine Fehlermeldung weil die Datei mit der anderen Programmversion erstellt wurde.

    Es geht nur um das einmalige einlesen bei der Portierung der Daten.
    Es sind auch relativ viele Einzeldateien.

    Habt Ihr eine Idee wie ich diese Daten dennoch wieder in die Structure laden kann ohne extra in der alten Software eine Exportroutine und in der neuen eine Importroutine schreiben zu müssen?
    Bilder
    • 24022021133221.jpg

      268,85 kB, 1.151×568, 67 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
    Brute Force: Du könntest die Structure der alten App in Dein Programm übernehmen, die Daten dort reinladen, dann die geladenen Daten in Instanzen der neuen Structure reinschreiben und die neuen Structure-Instanzen serialisieren. Vielleicht geht's eleganter
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    @dive26 Namespace und Klasse müssen denselben Namen tragen, ggf. sogar die Assembly.
    Teste das einfach mit 2 Studio-Instanzen, je eine Form und je (fast) dieselbe Datenklasse.
    Eine Form schreibt, die andere liest.
    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!
    Brute Force: Du könntest die Structure der alten App in Dein Programm übernehmen, die Daten dort reinladen, dann die geladenen Daten in Instanzen der neuen Structure reinschreiben und die neuen Structure-Instanzen serialisieren. Vielleicht geht's eleganter


    Ich verwende exakt die selbe Structure in meiner neuen App. Aber das "reinladen" funktioniert eben nicht.

    Namespace und Klasse müssen denselben Namen tragen, ggf. sogar die Assembly.

    Ja leider - gibt so wie es scheint keinen Workaround. Bin gerade dabei in der alten App eine Exportroutine zu schreiben und in der neuen eine Importroutine. Ist zwar viel Aufwand - aber es soll ja funktionieren. Auf die Structuren möchte ich nicht verzichten - damit lässt es sich für mich am einfachsten Arbeiten.
    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:

    gibt so wie es scheint keinen Workaround.
    Du könntesr auf XML-Serialisierung umsteigen.
    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!
    Habe 2 Apps. Einmal .NET-Framework-4.7.2-Winforms zum Speichern, einmal .NET-5.0-Winforms zum Laden. Habe in der 2. die 1. als Verweis eingetragen und dann geschrieben, dass mir der BinaryFormatter das Objekt in ein App1.WasauchimmerNamespace.Objekttyp laden soll. Klappt.

    VB.NET-Quellcode

    1. Namespace MyNamespace
    2. <Serializable>
    3. Public Class Bazz
    4. Property Foo As Integer
    5. End Class
    6. Public NotInheritable Class DataTransporter
    7. Public Shared Sub Load(Of T)(ByRef Bazz As T)
    8. Dim Formatter As New BinaryFormatter
    9. Using Stream As IO.FileStream = IO.File.OpenRead("2.dat")
    10. Dim InstanceOfOldType As WindowsApp1.MyNamespace.Bazz = Formatter.Deserialize(Stream) 'NameDerAltenAssembly.AlterNamespace.Typ
    11. 'hier dann die Schritt-für-Schritt-Umwandlung in den neuen Typ machen, Casting ist leider nicht möglich
    12. End Using
    13. End Sub
    14. End Class
    15. End Namespace


    mit CType wird dann sogar der Vorschlag gemacht, einen eigenen CType-Operator zu schreiben:

    VB.NET-Quellcode

    1. Public Shared Narrowing Operator CType(OldInstance As WindowsApp1.MyNamespace.Bazz) As Bazz
    2. End Operator

    Da kann man dann selber die Umwandlung reinzimmern.

    ##########

    Und die Umwandlung kann man sicherlich platzsparend mit Reflection machen.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

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

    Vielen Dank für Eure Antworten.

    Ich habs jetzt ganz anders gelöst - ist auch im Nachhinein gesehen für meinen Bedarf besser so. Und sogar gut, dass die Dateien inkompatibel waren.
    Denn ich habe festgestellt, dass meine neue Anwendung ohnehin andere Datensäzte braucht als die alte und es daher kein "Update", sondern (fast) eine Neuentwicklung wird.
    Mit dem Beibehalten der Datenkompatibilität legt man sich nur selbst Handfesseln an und man würde die Limits der "alten" Software wieder mitschleppen.

    Jetzt habe ich eine Export-Routine in der alten Software eingebaut und eine Importroutine in der neuen Software.
    Dann kann ich die Daten beim Importieren gleich in gewünschtem Format einlesen und ggf. der neuen Datenverarbeitung anpassen.
    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

    VaporiZed schrieb:

    Habe 2 Apps. Einmal .NET-Framework-4.7.2-Winforms zum Speichern, einmal .NET-5.0-Winforms zum Laden. Habe in der 2. die 1. als Verweis eingetragen und dann geschrieben, dass mir der BinaryFormatter das Objekt in ein App1.WasauchimmerNamespace.Objekttyp laden soll. Klappt.


    Vorsicht, reines Glück. BinaryFormatter zwischen .Net Framework und .NET sind grundsätzlich nicht kompatibel. Das funktioniert vielleicht nur für kleine Testprojekte. Bei komplexeren Objekten kommen aber Fehler wie z.B.: ​System.String kann nicht deserialisiert werden.
    Dann ist eh vorbei, da kommt man auch mit Surrogates nicht weiter.