Dateien auslesen

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 11 Antworten in diesem Thema. Der letzte Beitrag () ist von Tizian170.

    Dateien auslesen

    Hallo ihr lieben,

    klingt bestimmt einfach, aber ich krig es einfach nicht hin.
    Ich programmiere derzeit einen Dateimanager, und ich bekomme bei den Programm-"Optionen" ein paar Probleme.

    Das Programm speichert in einer "*.tes"-Datei die Optionen, die der Benutzer aktiviert/deaktiviert hat. Kein Problem soweit.

    Wer hätte es erwartet, muss das Programm die Datei logischerweise wieder auslesen. Hier mal der Dateiinhalt*:

    (Falls das Bild nicht oder falsch angezeigt wird, kann das Bild hier angeguckt werden.)
    Wie lade ich die Datei, dass auch die Einstellungen richtig angehackt sind?

    *Simulierter Dateiinhalt.

    Thank you! :thumbsup:
    Drücke auf Hilfreich, wenn dir dieser Post geholfen hat!
    Mein aktuelles Projekt
    Codar: 19%

    Link: bald
    Mach das Gegenteil, was Du beim Speichern machst. Aber ohne Code ist das hier Spekulatiusbacken.
    (Auch wenn ich denke, dass ich wüsste, wie es geht.)
    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.
    @Tizian170 Pack diese Settings in eine serialisierbare Klasse und speichere sie als XML-Datei ab (ggf. auch binär).
    Und dann das, was @VaporiZed schrieb:
    Settings befüllen
    Settings abspeichern
    ====
    Settings laden
    Settings auslesen.
    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!
    Erstmal danke, aber ...
    • die Settings möchte ich nicht nutzen, weil diese beim Kopieren des Programmordners gelöscht werden.
    • ich bin (wie immer) zu blöd, und weiß nicht, wie ich das mit der XML-Datei machen soll.
    Drücke auf Hilfreich, wenn dir dieser Post geholfen hat!
    Mein aktuelles Projekt
    Codar: 19%

    Link: bald

    Tizian170 schrieb:

    die Settings möchte ich nicht nutzen, weil diese beim Kopieren des Programmordners gelöscht werden.


    Warum? Du kannst doch selber aussuchen wo du das speicherst, also speicher die Settings halt im Programmordner.
    Grüße , xChRoNiKx

    Nützliche Links:
    Visual Studio Empfohlene Einstellungen | Try-Catch heißes Eisen
    Also ich speichere allgemein Daten (wenn ich keine Datenbank benutze) und eben auch Einstellungen immer in einer serialisieren XML-Datei - super einfach und ich muss mir keine Sorgen über die Formatierung machen.

    Leg dir also ne Klasse an, da kannst du dann deine gesamten Settings als Eigenschaften (je nach dem als bool oder string) ablegen - und dann serialisierst du diese Klasse als XML. - So würde ich das machen.

    Schau dir dafür am besten mal den NameSpace System.XML.Serializazion an....

    Anbei auch mal mein kleiner Code (nur C#) den ich zum Serialisieren von beliebigen Klassen nutze (ist generisch, also für jede Klasse einsetzbar) - der Code sollte eigentlich selbsterklärend sein.
    Spoiler anzeigen

    C#-Quellcode

    1. internal static class Serializer
    2. {
    3. public static void SaveXML<K>(string filename, K serializedObject)
    4. {
    5. try
    6. {
    7. XmlSerializer xml = new XmlSerializer(typeof(K));
    8. FileStream fs = new FileStream(filename, FileMode.Create);
    9. xml.Serialize(fs, serializedObject);
    10. fs.Close();
    11. }
    12. catch (Exception ex)
    13. {
    14. throw ex;
    15. }
    16. }
    17. public static K LoadXML<K>(string filename)
    18. {
    19. try
    20. {
    21. XmlSerializer xml = new XmlSerializer(typeof(K));
    22. K ret;
    23. FileStream fs = new FileStream(filename, FileMode.Open);
    24. ret = (K)xml.Deserialize(fs);
    25. fs.Close();
    26. return ret;
    27. }
    28. catch (Exception ex)
    29. {
    30. throw ex;
    31. }
    32. }
    33. }



    Wenn du noch Fragen hast, frag einfach.

    Viele Grüße
    Florian
    ----

    WebApps mit C#: Blazor
    @florian03 Das LoadXML() würde ich nicht in eine Exception laufen lassen, sondern im Falle einer Exception default(K) zurückgeben.
    Damit wäre gesichert, dass im Initialfall ohne XML-Datei das Programm nicht abschmiert.
    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!
    Jo, das ist eine gute Idee.
    Die Klasse ist auch keinesfalls "vollständig" und das Maß aller Dinge - ich verwende sie nur immer und hab sie auf meine Bedürfnisse angepasst. In meinen Programmen prüfe ich an anderer Stelle, ob die Datei vorhanden ist. Aber so wie du es gesagt hast ist es deutlich besser :thumbup:

    Grüße
    Florian
    ----

    WebApps mit C#: Blazor

    RodFromGermany schrieb:

    sondern im Falle einer Exception default(K) zurückgeben.

    Das würde ich anders machen. So wird nur Exception-Handling gegen null-Checks ausgetauscht, denn default(T) evaluiert im Zweifel zu null. Diesen Fall muss man dann jedesmal explizit prüfen, denn sonst landet man, beispielsweise bei fehlenden Dateien, anstatt einer konkreten und hilfreichen FileNotFoundException bei einer nichtssagenden NullReferenceException. Wenn, dann würde ich dafür sorgen, dass auch wirklich eine default-Instanz zurückgegeben wird:

    C#-Quellcode

    1. public static T LoadXML<T>(string filename) where T : new()
    2. {
    3. try
    4. {
    5. using (var fs = new FileStream(filename, FileMode.Open))
    6. {
    7. return (T)new XmlSerializer(typeof(T)).Deserialize(fs);
    8. }
    9. }
    10. catch
    11. {
    12. return new T();
    13. }
    14. }


    Das setzt natürlich voraus, dass in einer Setting-Klasse sinnvolle Standardwerte gesetzt sind.

    Spoiler anzeigen

    @florian03 Nur falls Interesse deinerseits besteht, weil du damals in Discord sehr lerninteressiert klangst: Du kannst deine Funktionen noch vereinfachen.

    C#-Quellcode

    1. catch (Exception ex)
    2. {
    3. throw ex;
    4. }

    So etwas sollte man vermeiden, da hier der StackTrace deiner Methode verändert wird. Sprich, die Fehlermeldung sagt im Zweifel nicht mehr, dass der Fehler z.B. in der Zeile ret = (K)xml.Deserialize(fs); aufgetreten ist, sondern in der Zeile throw ex;, denn hier wurde die Exception ja tatsächlich (neu) geworfen. Wenn du eine Exception in einem catch-Block "weiterwerfen" willst, kannst du einfach throw; schreiben, um das beschriebene Problem zu umgehen.
    In diesem Fall speziell bring ein Try/Catch allerdings gar nichts, denn du fängst die Exception nur, um sie weiterzuwerfen. Ich würde die Blöcke einfach entfernen. (Ich könnte mir allerdings denken, dass du vor dem Posten noch weiteren Code im Catch hattest, z.B. ein MessageBox.Show o.ä. - in diesem Fall kannst du den Kommentar einfach ignorieren ^^ ).

    C#-Quellcode

    1. XmlSerializer xml = new XmlSerializer(typeof(K));
    2. FileStream fs = new FileStream(filename, FileMode.Create);
    3. xml.Serialize(fs, serializedObject);
    4. fs.Close();

    Hier musst du auch aufpassen, speziell bei fs.Close();. Wenn in der Zeile obendrüber eine Exception fliegt, wird Close() nie aufgerufen und die Datei bleibt auf ewig (bis dein Programm terminiert) geschlossen. Hier ist es besser, einen using Block zu nutzen. Dieser garantiert, dass der FileStream immer geschlossen wird, auch wenn es eine Exception gibt.

    Zusammengefasst könnte SaveXML so aussehen:

    C#-Quellcode

    1. public static void SaveXML<T>(string filename, T serializedObject)
    2. {
    3. using (var fs = new FileStream(filename, FileMode.Create))
    4. {
    5. new XmlSerializer(typeof(T)).Serialize(fs, serializedObject);
    6. }
    7. }


    LoadXML() ist ja bereits über dem Spoiler zu sehen.

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

    Das bezieht sich jetzt nur auf die Anmerkung von @shad zu mir im vorherigen Spoiler :)

    Spoiler anzeigen


    shad schrieb:

    @florian03 Nur falls Interesse deinerseits besteht, weil du damals in Discord sehr lerninteressiert klangst: Du kannst deine Funktionen noch vereinfachen.


    Da haste dich recht erinnert :D - bin immer noch sehr lerninteressiert und freue mich über jeglichen Verbesserungsvorschlag.

    shad schrieb:

    In diesem Fall speziell bring ein Try/Catch allerdings gar nichts, denn du fängst die Exception nur, um sie weiterzuwerfen. Ich würde die Blöcke einfach entfernen. (Ich könnte mir allerdings denken, dass du vor dem Posten noch weiteren Code im Catch hattest, z.B. ein MessageBox.Show o.ä. - in diesem Fall kannst du den Kommentar einfach ignorieren ).


    Wie du es dir gedacht hattest - in meinen Projekten habe ich meistens einen Eintrag ins Log und die Öffnung eines Fehlerdialogs drinne - hätte aber natürlich den TE hier nur unnötig verwirrt.

    Bezüglich deiner 2. Verbesserung (und dem Tipp mit dem StackTrace) habe ich es nochmal versucht, die Klasse zu überarbeiten. Was sagst du :)

    C#-Quellcode

    1. internal static class Serializer
    2. {
    3. public static void SaveXML<K>(string filename, K serializedObject)
    4. {
    5. try
    6. {
    7. using (var fs = new FileStream(filename, FileMode.Create))
    8. {
    9. new XmlSerializer(typeof(K)).Serialize(fs, serializedObject);
    10. }
    11. }
    12. catch (Exception)
    13. {
    14. throw; //Für Entwickungszwecke
    15. //Sonst Fehlerdialog, Logeintrag, ...
    16. }
    17. }
    18. public static K LoadXML<K>(string filename)
    19. {
    20. try
    21. {
    22. using (var fs = new FileStream(filename, FileMode.Open))
    23. {
    24. return (K)new XmlSerializer(typeof(K)).Deserialize(fs);
    25. }
    26. }
    27. catch (Exception)
    28. {
    29. throw; //Für Entwickungszwecke
    30. //Sonst Fehlerdialog, Logeintrag, ...
    31. }
    32. }
    33. }


    Ich glaube man könnte im catch Block noch eine "if Anweisung" mit diesen Hashtags schreiben und damit abprüfen, ob sich das Programm im Debugmodus befindet. Dann kann man das "throw" in den Debug Block und das Öffnen eines Fehlerdialoges in den else Block schreiben...

    Der Code ist jetzt zumindest kürzer und besser geworden - Vielen Dank nochmal für die Tipps :thumbsup:



    Grüße
    ----

    WebApps mit C#: Blazor
    Ja, das sieht doch sehr gut aus! :)
    Man könnte noch 2 stilistische Punkte anmerken, aber diese haben keinerlei Auswirkungen auf den Flow, bzw. auf die Logik.
    Zum einen würde ich das <K> zu <T> umbenennen, da T der Standard in .NET ist - und Standards zu folgen ist immer die erste Wahl, es sei denn, es gibt einen triftigen Grund dafür, das Gegenteil zu tun. Das macht es anderen Leuten leichter, sich durch den Code zu arbeiten, da man nicht überlegen muss, warum denn jetzt genau K gewählt wurde und nicht T. (With that being said: Natürlich ist das jetzt meckern auf sehr hohem Niveau - wie gesagt, eigentlich macht es keinen Unterschied, es ist nur eine Frage des Codestils.)
    Zum anderen braucht man in deinem konkreten Fall kein catch (Exception). Ein catch { ... } reicht aus, wenn die Exception nicht weiterverarbeitet wird (was du in deiner echten Version aber eben tust, von daher ist auch diese Anmerkung für dein echtes Projekt irrelevant).

    Um jetzt auch wieder back-to-topic zu kommen poste ich hier die finale adaptierte Version, wie sie für den TE nützlich sein könnte. Credits also an @florian03 für die ursprüngliche Idee und das Posten des Codes:

    C#-Quellcode

    1. internal static class Serializer
    2. {
    3. public static void SaveXML<T>(string filename, T serializedObject)
    4. {
    5. using (var fs = new FileStream(filename, FileMode.Create))
    6. {
    7. new XmlSerializer(typeof(T)).Serialize(fs, serializedObject);
    8. }
    9. }
    10. public static T LoadXML<T>(string filename)
    11. {
    12. using (var fs = new FileStream(filename, FileMode.Open))
    13. {
    14. return (T)new XmlSerializer(typeof(T)).Deserialize(fs);
    15. }
    16. }
    17. }

    xChRoNiKx schrieb:

    Warum? Du kannst doch selber aussuchen wo du das speicherst, also speicher die Settings halt im Programmordner.

    Oh, danke. Da ich eh noch nicht so viel mit dem Settings zu tun hatte, hatte ich diese Funktion harnicht mehr im sinn. 8o
    So geht's natürlich auch. Thx.
    Drücke auf Hilfreich, wenn dir dieser Post geholfen hat!
    Mein aktuelles Projekt
    Codar: 19%

    Link: bald