Java Language
Ressourcen (auf Klassenpfad)
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:
- Die
Class
oder denClassLoader
finden, die die Ressource finden. - Die Ressource finden
- Abrufen des Byte-Streams für die Ressource.
- Lesen und Verarbeiten des Byte-Streams.
- 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; zBString.class
gibt Ihnen dasClass
Objekt für denString
Typ.Das
Object.getClass()
gibt Ihnen dasClass
Objekt für den Typ eines beliebigen Objekts."hello".getClass()
Beispiel"hello".getClass()
ist eine andere Möglichkeit,Class
vomString
Typ zu erhalten.Die
Class.forName(String)
-MethodeClass.forName(String)
falls erforderlich) eine Klasse dynamisch und gibt ihrClass
Objekt zurück. zBClass.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
undClass
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.
- Die
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
getResourcesmethods return an empty
Enumeration` zurück.Die zurückgegebenen URLs können mit
URL.toStream()
. Sie könnenfile:
URLs oder andere herkömmliche URLs sein. Wenn sich die Ressource jedoch in einer JAR-Datei befindet, handelt es sich umjar:
URLs, die die JAR-Datei und eine bestimmte Ressource darin angeben.Wenn Ihr Code eine
getResourceAsStream
Methode (oderURL.toStream()
) verwendet, um einenInputStream
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.