none
alle Dateien eines Ordners in Resources auslesen RRS feed

  • Frage

  • Hallo,

    ich will alle Dateien eines bestimmten Unterordners unter Resources auslesen, um diese später auf die Festplatte des Users zu speichern (siehe Thread standarddatei-bei-installation-mitgeben). Es handelt sich um png-Dateien.

    Ich bin soweit gekommen, dass ich alle Dateien aus Resources auslesen kann, zumindest erst einmal bestimmte Kopfdaten mit:

    List<string> listResults = new List<string>();
    foreach (PropertyInfo property in typeof(Properties.Resources).GetProperties
        (BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic))
    {
        string res = property.Name + ", " + property.GetValue(null, null);
        listResults.Add(res);
    }

    Aber ich kann nicht herausfinden, wie ich ausschließlich auf einen Unterordner von Resources zugreifen kann z.B. Resources/workplate. Von dort will ich alle Bilder "laden" und dann speichern (File.WriteAllText(path, property.Name + ".png")).

    Kann mir dabei jemand helfen?

    Herzliche Grüße!

    Frank


    www.energiewende-mach-ich-selbst.de

    Dienstag, 1. Juli 2014 13:55

Antworten

  • Die neuen Resourcendateien liegen im Namespace des Projekts, nicht in Properties.

    foreach (PropertyInfo property in typeof(Resource1).GetProperties(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic))
    {
        if (property.PropertyType == typeof(System.Drawing.Bitmap))//Nur Bilder abfragen
        {
            (property.GetValue(null) as System.Drawing.Bitmap).Save(property.Name + @".png");//Speichern (anderer Ort wäre besser um auch wirklich immer schreibrechte zu haben)
        }
    }
    PS: Ich meinte das Projekt, nicht die Projektmappe.


    Tom Lambert - C# MVP
    Bitte bewertet- und markiert Beiträge als Antwort. Danke.
    Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter
    Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets

    • Als Antwort markiert frank me Mittwoch, 2. Juli 2014 05:14
    Dienstag, 1. Juli 2014 15:11
    Moderator

Alle Antworten

  • Hallo,
    Stefan schlug dir in deiner anderen Frage die Verwendung von Anwendungsresourcn vor. Wenn du das auch hier verwenden willst, musst du dir eine 2. Resourcendatei hinzufügen. Mache dazu einen Rechtsklick auf die Projektmappe und wähle Hinzufügen > Neues Element... aus. Als Vorlage wählst du Resourcendatei. Dort fügst du dann wie gewohnt die Bilder hinzu. (Beispielsweise per Drag and Drop aus dem Projektmappenexplorer oder dem Windows Explorer.) Wenn du die Bilder sonst nicht in deiner Anwendung brauchst und sie trotzdem im Projektmappenexplorer haben willst, solltest du in den Eigenschaften Buildvorgang auf keine stellen.
    Je nachdem wie du die Resourcendatei genannt hast, wird jetzt eine Klasse generiert, die wie gewohnt die Resourcen als Eigenschaften enthält. (Standardmäßig Resource1/2/3/...)

    Eine Alternative zu den Resourcendateien ist, direkt über das WPF Resourcensystem zu gehen. Das bringt aber nichts, solange du die Dateien nicht auch in WPF verwenden willst. (Der Aufwand wäre größer.)


    Tom Lambert - C# MVP
    Bitte bewertet- und markiert Beiträge als Antwort. Danke.
    Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter
    Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets

    Dienstag, 1. Juli 2014 14:24
    Moderator
  • Hallo Frank,

    da gibt es keine Ordner, die man auslesen kann.

    Was mit einer Datei geschieht hängt davon ab, wie Du sie in das Projekt aufnimmst.

    Verwendest Du die Ressources - wie von Stefan in Standarddatei bei Installation mitgeben vorgeschlagen - so wird eine Verknüpfung über eine RESX Datei erzeugt und die Ressource darüber eingebettet, der Name der Standard-Ressource wäre <Namespace der Anwendung>.Properties.Resources.resources.

    Siehe Erstellen von Ressourcendateien für Desktop-Apps

    Dabei kommst Du an die Dateien nur indirekt entweder über die von VS erzeugte Properties.Resources dran oder in dem Du über einen ResourceManager darauf zugreifst. Was VS nur für Dich versteckt => Schau mal in erzeugte Resources.Designer.cs Datei.

    Die Alternative wäre eine Datei über eingebettete Ressource einzubetten. Dabei wird jede Datei einzeln als Ressource eingebettet. Dabei entsteht ein Name nach dem Muster <Standard-Namespace der Anwendung>.Verzeichnis.Dateiname. Wobei die Namensbestandteile durch einen Punkt (".") getrennt werden - bei Unterverzeichnissen werden "\" durch einen "." ersetzt.

    Was sich da alles so findet kannst Du herausfinden mittels:

                Assembly thisAssembly = this.GetType().Assembly;
                foreach (var resourceName in thisAssembly.GetManifestResourceNames())
                    Console.WriteLine(resourceName);

    Auch dort müsstest Du die Namen auseinander pflücken und wieder in einen Verzeichnis-Baum umwandeln.

    Der Rest läuft in etwa ab wie beschrieben in Gewusst wie: Einbetten und Zugriff auf Ressourcen mithilfe von Visual C#

    Gruß Elmar

    Dienstag, 1. Juli 2014 14:58
  • Danke Tom,

    ich habe das so gemacht
    (mit dem Unterschied, dass ich die Ressourcendatei dem Projekt und nicht der Projektmappe hinzugefügt habe).

    Ich habe nun eine schöne Datei mit den Bildern darin. Aber der Zugriff auf diese Datei gelingt mir leider ebenso wenig wie zuvor auf einen Unterordner von Resources, da ich mit Properties.Resources nur auf den (bisherigen) Resources-Ordner zugreifen kann. Einen Properties.MyNewResources gibt es nicht. Eine andere Lösung als Properties.Resources habe ich nicht gefunden.

    Wie kann ich durch die Bilder im neuen Ressourcen-Ordner iterieren, um sie auf die HD zu speichen?


    www.energiewende-mach-ich-selbst.de


    • Bearbeitet frank me Dienstag, 1. Juli 2014 15:04
    Dienstag, 1. Juli 2014 15:04
  • Die neuen Resourcendateien liegen im Namespace des Projekts, nicht in Properties.

    foreach (PropertyInfo property in typeof(Resource1).GetProperties(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic))
    {
        if (property.PropertyType == typeof(System.Drawing.Bitmap))//Nur Bilder abfragen
        {
            (property.GetValue(null) as System.Drawing.Bitmap).Save(property.Name + @".png");//Speichern (anderer Ort wäre besser um auch wirklich immer schreibrechte zu haben)
        }
    }
    PS: Ich meinte das Projekt, nicht die Projektmappe.


    Tom Lambert - C# MVP
    Bitte bewertet- und markiert Beiträge als Antwort. Danke.
    Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter
    Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets

    • Als Antwort markiert frank me Mittwoch, 2. Juli 2014 05:14
    Dienstag, 1. Juli 2014 15:11
    Moderator
  • Hallo zusammen,

    man sollte sich klar sein, dass man bei der von Tom gezeigten Variante ziemlich Speicher braucht, da man die Daten via System.Drawing.Bitmap in den Speicher lädt. Nebenbei empfiehlt sich für oben ein using, damit der Speicher freigegeben wird.

    Verwendet man verlustbehaftete Dateiformate (wie JPG-Bilder) wird durch das Abrufen als Bitmap und Speichern eine neue Datei erzeugt und diese ist nicht (immer) identisch.

    Verwendet man eine Embedded Resource kann man Speicher sparen. Nur muss man sich irgendwie die Namen selbst extrahieren - IMO vernachlässigbar zum "Pseudo-Komfort" von GetProperty.

    Mini-Beispiel anhand einer (etwa 230 KB großen JPG) Datei, die einmal via GetObject als Bitmap, ein anderes Mal als Embedded Ressource via  GetManifestResourceStream abgerufen wird:

                // Verwendete Datei ca. 230 KB groß
    
                var gcmemory = GC.GetTotalMemory(true);
                using (var inputStream = Assembly.GetEntryAssembly().GetManifestResourceStream("ElmarBoye.Samples.Wpf.Resources.Image2.jpg"))
                using (var outputStream = System.IO.File.Create(@"C:\TEMP\Image2_1.jpg"))
                    inputStream.CopyTo(outputStream);
                // Memory Stream: 1.709.156 => 90.136
                Console.WriteLine("Memory Stream: {0:N0} => {1:N0}", gcmemory, GC.GetTotalMemory(false) - gcmemory);
    
                var gcmemory2 = GC.GetTotalMemory(true);
                using (var bmp = Properties.Resources.Image2)
                    bmp.Save(@"C:\TEMP\Image2_2.jpg");
                // Bitmap: 1.709.348 => 1.006.732
                Console.WriteLine("Bitmap: {0:N0} => {1:N0}", gcmemory2, GC.GetTotalMemory(false) - gcmemory2);

    Im Kommentar die Ausgaben nach dem dritten Durchlauf, wobei die zweite Zahl die Differenz darstellt.

    Und will man knickerig sein, kann man auch eine ZIP/7.Z Datei separat mitliefern und diese extrahieren. Was den Vorteil hat, dass man die Datei unabhängig vom Programm austauschen kann - ausgenommen den Fall gerade das soll nicht sein.

    Gruß Elmar

    • Bearbeitet Elmar Boye Mittwoch, 2. Juli 2014 08:49
    Mittwoch, 2. Juli 2014 08:47