Suche…


Einführung

Java ermöglicht das Abrufen von dateibasierten Ressourcen, die in einer JAR-Datei neben kompilierten Klassen gespeichert sind. Dieses Thema konzentriert sich darauf, diese Ressourcen zu laden und für Ihren Code verfügbar zu machen.

Bemerkungen

Eine Ressource besteht aus dateiähnlichen Daten mit einem pfadähnlichen Namen, der sich im Klassenpfad befindet. Die häufigste Verwendung von Ressourcen ist das Bündeln von Anwendungsbildern, Sounds und schreibgeschützten Daten (z. B. Standardkonfiguration).

Auf die Ressourcen kann mit den Methoden ClassLoader.getResource und ClassLoader.getResourceAsStream zugegriffen werden. Der häufigste Anwendungsfall besteht darin, Ressourcen in demselben Paket wie die Klasse abzulegen, in der sie gelesen werden. Die Methoden Class.getResource und Class.getResourceAsStream dienen diesem allgemeinen Anwendungsfall.

Der einzige Unterschied zwischen einer getResource-Methode und der getResourceAsStream-Methode besteht darin, dass erstere eine URL zurückgibt, während letztere diese URL öffnet und einen InputStream zurückgibt.

Die Methoden von ClassLoader akzeptieren einen pfadähnlichen Ressourcennamen als Argument und durchsuchen jede Position im Classpath des ClassLoader nach einem Eintrag, der diesem Namen entspricht.

  • Wenn ein Classpath-Speicherort eine JAR-Datei ist, wird ein Jar-Eintrag mit dem angegebenen Namen als Übereinstimmung betrachtet.
  • Wenn ein Classpath-Speicherort ein Verzeichnis ist, wird eine relative Datei unter diesem Verzeichnis mit dem angegebenen Namen als Übereinstimmung betrachtet.

Der Ressourcenname ähnelt dem Pfadteil einer relativen URL. Auf allen Plattformen werden Schrägstriche ( / ) als Verzeichnisseparatoren verwendet. Es darf nicht mit einem Schrägstrich beginnen.

Die entsprechenden Methoden von Class sind ähnlich, außer:

  • Der Ressourcenname kann mit einem Schrägstrich beginnen. In diesem Fall wird der anfängliche Schrägstrich entfernt und der Rest des Namens an die entsprechende Methode von ClassLoader übergeben.
  • Wenn der Ressourcenname nicht mit einem Schrägstrich beginnt, wird er als relativ zu der Klasse behandelt, deren getResource- oder getResourceAsStream-Methode aufgerufen wird. Der tatsächliche Ressourcenname wird zu Paket / Name , wobei Paket der Name des Pakets ist, zu dem die Klasse gehört, wobei jeder Punkt durch einen Schrägstrich ersetzt wird, und Name das ursprüngliche Argument für die Methode ist.

Zum Beispiel:

package com.example;

public class ExampleApplication {
    public void readImage()
    throws IOException {

        URL imageURL = ExampleApplication.class.getResource("icon.png");

        // The above statement is identical to:
        // ClassLoader loader = ExampleApplication.class.getClassLoader();
        // URL imageURL = loader.getResource("com/example/icon.png");

        Image image = ImageIO.read(imageURL);
    }
}

Ressourcen sollten in benannten Paketen und nicht im Stammverzeichnis einer JAR-Datei abgelegt werden. Aus demselben Grund werden Klassen in Paketen platziert: Um Kollisionen zwischen mehreren Anbietern zu vermeiden. Wenn sich zum Beispiel mehrere .jar-Dateien im Klassenpfad befinden und mehr als eine von ihnen einen Eintrag config.properties im Stammverzeichnis enthält, geben Aufrufe der Methoden getResource oder getResourceAsStream die Datei config.properties aus dem ersten Verzeichnis zurück der Klassenpfad Dies ist kein vorhersagbares Verhalten in Umgebungen, in denen die Klassenpfadreihenfolge nicht direkt von der Anwendung gesteuert wird, wie z. B. Java EE.

Alle getResource- und getResourceAsStream-Methoden geben null wenn die angegebene Ressource nicht vorhanden ist. Da der Anwendung zum Erstellungszeitpunkt Ressourcen hinzugefügt werden müssen, sollten deren Speicherorte bekannt sein, wenn der Code geschrieben wird. Ein Fehler beim Finden einer Ressource zur Laufzeit ist in der Regel das Ergebnis eines Programmierfehlers.

Ressourcen sind schreibgeschützt. Es ist nicht möglich, auf eine Ressource zu schreiben. Anfänger begehen häufig den Fehler, anzunehmen, dass die Ressource bei der Entwicklung in einer IDE (wie Eclipse) eine separate physische Datei ist. Daher ist es sicher, dass sie im allgemeinen Fall als separate physische Datei behandelt wird. Dies ist jedoch nicht korrekt. Anwendungen werden fast immer als Archive wie JAR- oder WAR-Dateien verteilt, und in solchen Fällen ist eine Ressource keine separate Datei und kann nicht beschrieben werden. (Die getFile-Methode der URL-Klasse ist keine Lösung für dieses Problem; sie gibt trotz ihres Namens lediglich den Pfadteil einer URL zurück, der keinesfalls als gültiger Dateiname garantiert ist.)

Es gibt keine sichere Möglichkeit, Ressourcen zur Laufzeit aufzulisten. Da wiederum die Entwickler dafür verantwortlich sind, Ressourcendateien zur Buildzeit hinzuzufügen, sollten sie ihre Pfade bereits kennen. Es gibt zwar Problemumgehungen, sie sind jedoch nicht zuverlässig und scheitern schließlich.

Laden eines Bildes von einer Ressource

So laden Sie ein gebündeltes Bild:

package com.example;

public class ExampleApplication {
    private Image getIcon() throws IOException {
        URL imageURL = ExampleApplication.class.getResource("icon.png");
        return ImageIO.read(imageURL);
    }
}

Standardkonfiguration wird geladen

So lesen Sie die Standardkonfigurationseigenschaften:

package com.example;

public class ExampleApplication {
    private Properties getDefaults() throws IOException {
        Properties defaults = new Properties();

        try (InputStream defaultsStream =
            ExampleApplication.class.getResourceAsStream("config.properties")) {

            defaults.load(defaultsStream);
        }

        return defaults;
    }
}

Laden der gleichnamigen Ressource aus mehreren JARs

Eine Ressource mit demselben Pfad und Namen kann in mehr als einer JAR-Datei im Klassenpfad vorhanden sein. Häufige Fälle sind Ressourcen, die einer Konvention folgen oder Teil einer Verpackungsspezifikation sind. Beispiele für solche Ressourcen sind

  • META-INF / MANIFEST.MF
  • META-INF / beans.xml (CDI-Spezifikation)
  • ServiceLoader-Eigenschaften, die Implementierungsanbieter enthalten

Um auf alle diese Ressourcen in verschiedenen Gläsern zugreifen zu können , muss ein ClassLoader verwendet werden, der über eine Methode dafür verfügt. Die zurückgegebene Enumeration kann bequem mit einer Collections-Funktion in eine List konvertiert werden.

Enumeration<URL> resEnum = MyClass.class.getClassLoader().getResources("META-INF/MANIFEST.MF");
ArrayList<URL> resources = Collections.list(resEnum);

Ressourcen mit einem Classloader finden und lesen

Das Laden von Ressourcen in Java umfasst die folgenden Schritte:

  1. Die Class oder den ClassLoader finden, die die Ressource finden.
  2. Die Ressource finden
  3. Abrufen des Byte-Streams für die Ressource.
  4. Lesen und Verarbeiten des Byte-Streams.
  5. Den Bytestrom schließen.

Die letzten drei Schritte werden normalerweise ausgeführt, indem die URL an eine Bibliotheksmethode oder einen Konstruktor übergeben wird, um die Ressource zu laden. In diesem Fall verwenden Sie normalerweise eine getResource Methode. Es ist auch möglich, die Ressourcendaten im Anwendungscode zu lesen. In diesem Fall verwenden Sie normalerweise getResourceAsStream .

Absolute und relative Ressourcenpfade

Ressourcen, die aus dem Klassenpfad geladen werden können, werden durch einen Pfad angegeben . Die Syntax des Pfads ähnelt einem UNIX / Linux-Dateipfad. Es besteht aus einfachen Namen, die durch Schrägstrich ( / ) getrennt sind. Ein relativer Pfad beginnt mit einem Namen und ein absoluter Pfad beginnt mit einem Trennzeichen.

Wie in den Classpath-Beispielen beschrieben, definiert der Classpath einer JVM einen Namespace, indem die Namespaces der Verzeichnisse und JAR- oder ZIP-Dateien im Classpath eingeblendet werden. Wenn ein absoluter Pfad aufgelöst wird, interpretieren die Klassenladeprogramme den Anfang / als die Wurzel des Namespaces. Im Gegensatz dazu kann ein relativer Pfad im Namensraum relativ zu einem beliebigen „Ordner“ gelöst werden. Der verwendete Ordner hängt von dem Objekt ab, mit dem Sie den Pfad auflösen.

Eine Klasse oder einen Klassenlader erhalten

Eine Ressource kann entweder über ein Class Objekt oder ein ClassLoader Objekt ClassLoader werden. Ein Class Objekt kann relative Pfade auflösen, sodass Sie normalerweise einen dieser Pfade verwenden, wenn Sie über eine (Klassen-) relative Ressource verfügen. Es gibt verschiedene Möglichkeiten, ein Class Objekt zu erhalten. Zum Beispiel:

  • Eine Klasse wörtliche wird Ihnen das Class - Objekt für jede Klasse , die Sie in Java - Quellcode nennen kann; zB String.class gibt Ihnen das Class Objekt für den String Typ.

  • Das Object.getClass() gibt Ihnen das Class Objekt für den Typ eines beliebigen Objekts. "hello".getClass() Beispiel "hello".getClass() ist eine andere Möglichkeit, Class vom String Typ zu erhalten.

  • Die Class.forName(String) -Methode Class.forName(String) falls erforderlich) eine Klasse dynamisch und gibt ihr Class Objekt zurück. zB Class.forName("java.lang.String") .

Ein ClassLoader Objekt wird normalerweise durch Aufrufen von getClassLoader() für ein Class Objekt abgerufen. Es ist auch möglich, den Standard-Classloader der JVM mithilfe der statischen ClassLoader.getSystemClassLoader() -Methode zu erhalten.

Die get Methoden

Sobald Sie eine haben Class oder ClassLoader - Instanz können Sie eine Ressource finden, eine der folgenden Methoden verwenden:

Methoden Beschreibung
ClassLoader.getResource(path)
ClassLoader.getResources(path)
Gibt eine URL zurück, die den Ort der Ressource mit dem angegebenen Pfad darstellt.
ClassLoader.getResources(path)
Class.getResources(path)
Gibt eine Enumeration<URL> , die die URLs foo.bar , die zum foo.bar der foo.bar Ressource verwendet werden können. siehe unten.
ClassLoader.getResourceAsStream(path)
Class.getResourceStream(path)
Gibt einen InputStream aus dem Sie den Inhalt der foo.bar Ressource als Folge von Bytes lesen können.

Anmerkungen:

  • Der Hauptunterschied zwischen den ClassLoader und Class Versionen der Methoden besteht in der Art und Weise, wie relative Pfade interpretiert werden.

    • Die Class lösen einen relativen Pfad im "Ordner" auf, der dem Klassenpaket entspricht.
    • Die ClassLoader Methoden behandeln relative Pfade so, als wären sie absolut. dh sie lösen sie im "Root-Ordner" des Classpath-Namespaces auf.
  • Wenn die angeforderte Ressource (oder Ressourcen) nicht gefunden werden können, geben die methods return getResource und getResourceAsStream null zurück , and the methods return an empty getResources methods return an empty Enumeration` zurück.

  • Die zurückgegebenen URLs können mit URL.toStream() . Sie können file: URLs oder andere herkömmliche URLs sein. Wenn sich die Ressource jedoch in einer JAR-Datei befindet, handelt es sich um jar: URLs, die die JAR-Datei und eine bestimmte Ressource darin angeben.

  • Wenn Ihr Code eine getResourceAsStream Methode (oder URL.toStream() ) verwendet, um einen InputStream zu erhalten, ist er für das Schließen des Stream-Objekts verantwortlich. Wenn der Stream nicht geschlossen wird, kann dies zu einem Ressourcenleck führen.



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow