Hilfsklasse zu eingebetteten Ressourcen

    • VB.NET

    Es gibt 6 Antworten in diesem Thema. Der letzte Beitrag () ist von nafets3646.

      Hilfsklasse zu eingebetteten Ressourcen

      Hallo alle zusammen,
      ich habe für euch eine Klasse, welche den Umgang mit eingebetteten Ressourcen vereinfachen soll. Als Inspiration diente dieser Thread: [Allgemein] Video im Programm einfügen. Hier ist mir aufgefallen, dass es keinen einheitlichen Weg gibt, Ressourcen abzuspeichern (zum Beispiel muss man für Bilder den Umweg über einen ImageConverter gehen). Über die eingebetteten Ressourcen geht das zwar, allerdings ist die Vorgehensweise nicht so simpel und daher für Anfänger und Leute, welche auf dem Gebiet noch nicht so erfahren sind nicht wirklich geeignet.
      Die Klasse löst das Problem, indem sie einen einfachen Weg bietet, Ressourcen zu durchsuchen, den dazugehörigen Stream zu erhalten und abzuspeichern und das mit der eigenen oder sogar mit einer fremden Assembly. Sie ist übersichtlich aufgebaut und alle Methoden sind mit XML-Kommentaren versehen. Das System sollte mit allen Dateitypen zurechtkommen (getestet wurden docx, doc, mp4, flv, png, jpg, pdf, zip, ico und noch ein paar mehr).

      Code:
      VB (Original)

      VB.NET-Quellcode

      1. Imports System.IO
      2. Imports System.Reflection
      3. Public Class EmbeddedResourceHelper
      4. Private _SourceAssembly As Assembly = Nothing
      5. ''' <summary>
      6. ''' Die Assembly, welche durchsucht werden soll
      7. ''' </summary>
      8. Public Property SourceAssembly As Assembly
      9. Get
      10. Return _SourceAssembly
      11. End Get
      12. Private Set(value As Assembly)
      13. _SourceAssembly = value
      14. End Set
      15. End Property
      16. ''' <summary>
      17. ''' Erstellt einen neuen EmbeddedResourceHelper
      18. ''' </summary>
      19. Public Sub New()
      20. Me.SourceAssembly = Assembly.GetCallingAssembly()
      21. End Sub
      22. ''' <summary>
      23. ''' Erstellt einen neuen EmbeddedResourceHelper
      24. ''' </summary>
      25. ''' <param name="assembly">Die Assembly, welche durchsucht werden soll</param>
      26. Public Sub New(assembly As Assembly)
      27. Me.SourceAssembly = assembly
      28. End Sub
      29. ''' <summary>
      30. ''' Gibt den zu einer Ressource gehörenden Stream aus
      31. ''' </summary>
      32. ''' <param name="fileName">Der Name der Ressource, nach der gesucht werden soll</param>
      33. ''' <returns>Den zu der Ressource gehörenden Stream</returns>
      34. Public Function GetStream(fileName As String) As Stream
      35. Dim AvailableResources = GetResourceNames()
      36. If AvailableResources.Contains(fileName) Then
      37. Return SourceAssembly.GetManifestResourceStream(fileName)
      38. Else
      39. Dim MatchingResource = AvailableResources.FirstOrDefault(Function(resourcePath) resourcePath.EndsWith(fileName))
      40. If MatchingResource IsNot Nothing Then
      41. Return SourceAssembly.GetManifestResourceStream(MatchingResource)
      42. Else
      43. Throw New ArgumentException("Ressource wurde nicht gefunden", "fileName")
      44. End If
      45. End If
      46. End Function
      47. ''' <summary>
      48. ''' Schreibt eine Ressource in eine Datei
      49. ''' </summary>
      50. ''' <param name="fileName">Der Name der Originaldatei</param>
      51. ''' <param name="outputPath">Der Pfad, in den sie geschrieben werden soll</param>
      52. Public Function WriteResourceToFile(fileName As String, outputPath As String) As FileInfo
      53. Using ResourceStream = GetStream(fileName)
      54. Dim OutputFile As New FileInfo(Path.Combine(outputPath, fileName))
      55. Using OutputStream = OutputFile.Open(FileMode.Create)
      56. ResourceStream.CopyTo(OutputStream)
      57. 'OutputStream.Close()
      58. End Using
      59. Return OutputFile
      60. End Using
      61. End Function
      62. ''' <summary>
      63. ''' Gibt die Namen aller in die Assembly eingebetteten Ressourcen aus
      64. ''' </summary>
      65. ''' <returns>Die Namen aller in die Assembly eingebetteten Ressourcen</returns>
      66. Public Function GetResourceNames() As IEnumerable(Of String)
      67. Return SourceAssembly.GetManifestResourceNames()
      68. End Function
      69. End Class
      C#

      C-Quellcode

      1. using System.IO;
      2. using System.Reflection;
      3. public class EmbeddedResourceHelper
      4. {
      5. private Assembly _SourceAssembly = null;
      6. /// <summary>
      7. /// Die Assembly, welche durchsucht werden soll
      8. /// </summary>
      9. public Assembly SourceAssembly {
      10. get { return _SourceAssembly; }
      11. private set { _SourceAssembly = value; }
      12. }
      13. /// <summary>
      14. /// Erstellt einen neuen EmbeddedResourceHelper
      15. /// </summary>
      16. public EmbeddedResourceHelper()
      17. {
      18. this.SourceAssembly = Assembly.GetCallingAssembly();
      19. }
      20. /// <summary>
      21. /// Erstellt einen neuen EmbeddedResourceHelper
      22. /// </summary>
      23. /// <param name="assembly">Die Assembly, welche durchsucht werden soll</param>
      24. public EmbeddedResourceHelper(Assembly assembly)
      25. {
      26. this.SourceAssembly = assembly;
      27. }
      28. /// <summary>
      29. /// Gibt den zu einer Ressource gehörenden Stream aus
      30. /// </summary>
      31. /// <param name="fileName">Der Name der Ressource, nach der gesucht werden soll</param>
      32. /// <returns>Den zu der Ressource gehörenden Stream</returns>
      33. public Stream GetStream(string fileName)
      34. {
      35. var AvailableResources = GetResourceNames();
      36. if (AvailableResources.Contains(fileName)) {
      37. return SourceAssembly.GetManifestResourceStream(fileName);
      38. } else {
      39. var MatchingResource = AvailableResources.FirstOrDefault(resourcePath => resourcePath.EndsWith(fileName));
      40. if (MatchingResource != null) {
      41. return SourceAssembly.GetManifestResourceStream(MatchingResource);
      42. } else {
      43. throw new ArgumentException("Ressource wurde nicht gefunden", "fileName");
      44. }
      45. }
      46. }
      47. /// <summary>
      48. /// Schreibt eine Ressource in eine Datei
      49. /// </summary>
      50. /// <param name="fileName">Der Name der Originaldatei</param>
      51. /// <param name="outputPath">Der Pfad, in den sie geschrieben werden soll</param>
      52. public FileInfo WriteResourceToFile(string fileName, string outputPath)
      53. {
      54. using (ResourceStream == GetStream(fileName)) {
      55. FileInfo OutputFile = new FileInfo(Path.Combine(outputPath, fileName));
      56. using (OutputStream == OutputFile.Open(FileMode.Create)) {
      57. ResourceStream.CopyTo(OutputStream);
      58. //OutputStream.Close()
      59. }
      60. return OutputFile;
      61. }
      62. }
      63. /// <summary>
      64. /// Gibt die Namen aller in die Assembly eingebetteten Ressourcen aus
      65. /// </summary>
      66. /// <returns>Die Namen aller in die Assembly eingebetteten Ressourcen</returns>
      67. public IEnumerable<string> GetResourceNames()
      68. {
      69. return SourceAssembly.GetManifestResourceNames();
      70. }
      71. }

      Klassendiagramm:


      Benutzung
      Schritt 1, Klasse zum Projekt hinzufügen:
      • Projekt > Klasse hinzufügen > Namen geben > Code einfügen
      Schritt 2, Ressourcen hinzufügen:
      1. Projekt > Vorhandenes Element hinzufügen > Datei auswählen
      2. Datei im Projektmappenexplorer auswählen und in den Eigenschaften den Buildvorgang auf "Eingebettete Ressource" stellen
      Schritt 3, Ressource im Programm abrufen:
      • Methode 1, Datei abspeichern:
        Dafür verwenden wir die Methode WriteResourceToFile. Die Benutzung ist einfach, wir geben den Namen der Originaldatei und den Ausgabeordner ein und kriegen eine FileInfo auf die erstellte Datei zurück. Das könnte beispielsweise so aussehen:

        VB.NET-Quellcode

        1. 'Neuen EmbeddedResourceHelper auf die eigene Assembly erstellen
        2. Dim Helper As New EmbeddedResourceHelper()
        3. 'Die Datei TestPNG.png aus den Ressourcen in den Temp-Ordner schreiben
        4. Dim OutputFile As FileInfo = Helper.WriteResourceToFile("TestPNG.png", Path.GetTempPath)

        Mit der FileInfo, welche wir bekommen haben, können wir jetzt vieles machen, beispielsweise uns den Pfad der Datei daraus holen und sie öffnen:

        VB.NET-Quellcode

        1. 'Pfad holen
        2. Dim OutputFilePath As String = OutputFile.FullName
        3. 'Datei öffnen
        4. Process.Start(OutputFilePath)

      • Methode 2, Stream holen:
        Wir können uns auch den Stream auf die Datei holen, indem wir die Funktion GetStream verwenden. Das kann zum Beispiel hilfreich sein, wenn man nur den Inhalt der Datei in Textform bekommen möchte:

        VB.NET-Quellcode

        1. 'Neuen EmbeddedResourceHelper auf die eigene Assembly erstellen
        2. Dim Helper As New EmbeddedResourceHelper()
        3. 'Stream auf die Datei TestTXT.txt holen
        4. Dim OutputStream As Stream = Helper.GetStream("TestTXT.txt")

        Aus dem Stream könnte man jetzt beispielsweise den Text auslesen (wenn es eine Textdatei ist) und diesen ausgeben:

        VB.NET-Quellcode

        1. 'Streamreader auf den Stream erstellen
        2. Dim OutputStreamReader As New StreamReader(OutputStream)
        3. 'Den Stream in einen String lesen
        4. Dim OutputText As String = OutputStreamReader.ReadToEnd()
        5. 'Den String ausgeben
        6. MessageBox.Show(OutputText)


      Changelog

      Version 0.1
      Erste funktionsfähige Version
      Version 0.2
      Kleine Verbesserungen (Danke an ~blaze~ für den Hinweis)


      Ich hoffe, dass einigen dieser Code weiterhelfen wird :).
      MfG Stefan

      Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „nafets3646“ ()

      Weil der Wert bereits im Konstruktor auf einen entsprechenden Wert festgelegt wurde. Das ist auch sinnvoller, als eine Property zu definieren, über die das ganze abläuft.
      Was mir noch aufgefallen ist: Statt .Count() > 0 solltest du .Any() verwenden. Count muss erst alle Elemente des Enumerable durchlaufen und dabei eine Zählvariable inkrementieren. Du kannst theoretisch aber auch FirstOrDefault verwenden und auf Nothing überprüfen. Es ist nicht notwendig, bei IO.File.Delete zu überprüfen, ob die Datei existiert. Außerdem ist es eleganter, einfach direkt System.IO.FileStream im Create-Modus zu erzeugen. Dateien können zwischen zwei Aufrufen noch geändert werden, wenn ein zweites Programm Änderungen daran vornimmt, daher sollten die Operationen atomar sein. Zwischen einer Exists-Abfrage und einem Delete-Aufruf kann z.B. die Datei bereits gelöscht werden.

      Gruß
      ~blaze~