Zoeken…


Invoering

Met Java kunnen bestandsgebaseerde bronnen worden opgehaald die in een JAR zijn opgeslagen naast gecompileerde klassen. Dit onderwerp is gericht op het laden van deze bronnen en deze beschikbaar maken voor uw code.

Opmerkingen

Een resource is bestandachtige gegevens met een padachtige naam, die zich in het classpath bevindt. Het meest voorkomende gebruik van bronnen is het bundelen van toepassingsafbeeldingen, geluiden en alleen-lezen gegevens (zoals standaardconfiguratie).

Bronnen zijn toegankelijk met de methoden ClassLoader.getResource en ClassLoader.getResourceAsStream . De meest voorkomende use case is om bronnen in hetzelfde pakket te plaatsen als de klasse die ze leest; de methoden Class.getResource en Class.getResourceAsStream zijn geschikt voor dit veelvoorkomende gebruik.

Het enige verschil tussen een getResource-methode en getResourceAsStream-methode is dat de eerste een URL retourneert, terwijl de laatste die URL opent en een InputStream retourneert.

De methoden van ClassLoader accepteren een padachtige bronnaam als argument en zoeken op elke locatie in het Classpath van de ClassLoader naar een item dat overeenkomt met die naam.

  • Als een classpath-locatie een .jar-bestand is, wordt een jar-item met de opgegeven naam als een overeenkomst beschouwd.
  • Als een classpath-locatie een map is, wordt een relatief bestand onder die map met de opgegeven naam als een overeenkomst beschouwd.

De bronnaam is vergelijkbaar met het padgedeelte van een relatieve URL. Op alle platforms gebruikt het voorwaartse schuine strepen ( / ) als scheidingstekens voor mappen. Het mag niet beginnen met een schuine streep.

De overeenkomstige methoden van Klasse zijn vergelijkbaar, behalve:

  • De bronnaam kan beginnen met een schuine streep, in welk geval die schuine streep wordt verwijderd en de rest van de naam wordt doorgegeven aan de overeenkomstige methode van ClassLoader.
  • Als de bronnaam niet begint met een schuine streep, wordt deze behandeld ten opzichte van de klasse waarvan de methode getResource of getResourceAsStream wordt aangeroepen. De werkelijke bronnaam wordt pakket / naam , waarbij pakket de naam is van het pakket waartoe de klasse behoort, waarbij elke periode wordt vervangen door een schuine streep en naam het oorspronkelijke argument is dat aan de methode is gegeven.

Bijvoorbeeld:

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);
    }
}

Bronnen moeten in benoemde pakketten worden geplaatst, in plaats van in de root van een .jar-bestand, om dezelfde reden worden klassen in pakketten geplaatst: Om botsingen tussen meerdere leveranciers te voorkomen. Als er bijvoorbeeld meerdere .jar-bestanden in het classpath staan en er meer dan één in de root een item config.properties bevat, zullen aanroepen van de methoden getResource of getResourceAsStream de config.properties terugsturen van welke .jar het eerst wordt vermeld in het klassenpad. Dit is geen voorspelbaar gedrag in omgevingen waar de classpath-volgorde niet onder de directe controle van de toepassing staat, zoals Java EE.

Alle getResource- en getResourceAsStream-methoden retourneren null als de opgegeven bron niet bestaat. Aangezien bronnen tijdens het bouwen aan de applicatie moeten worden toegevoegd, moeten hun locaties bekend zijn wanneer de code wordt geschreven; het niet vinden van een bron tijdens runtime is meestal het gevolg van een programmeerfout.

Bronnen zijn alleen-lezen. Er is geen manier om naar een bron te schrijven. Beginnende ontwikkelaars maken vaak de fout om aan te nemen dat, aangezien de bron een afzonderlijk fysiek bestand is bij het ontwikkelen in een IDE (zoals Eclipse), het in het algemeen veilig is om het als een afzonderlijk fysiek bestand te behandelen. Dit is echter niet correct; toepassingen worden bijna altijd gedistribueerd als archieven zoals .jar- of .war-bestanden, en in dergelijke gevallen zal een bron geen afzonderlijk bestand zijn en niet beschrijfbaar zijn. (De getFile-methode van de URL-klasse is hiervoor geen oplossing; ondanks de naam retourneert deze alleen het padgedeelte van een URL, dat geenszins gegarandeerd een geldige bestandsnaam is.)

Er is geen veilige manier om bronnen tijdens runtime te vermelden. Nogmaals, aangezien de ontwikkelaars verantwoordelijk zijn voor het toevoegen van bronbestanden aan de toepassing tijdens het bouwen, moeten ontwikkelaars hun paden al kennen. Hoewel er tijdelijke oplossingen zijn, zijn ze niet betrouwbaar en zullen ze uiteindelijk mislukken.

Een afbeelding laden vanuit een bron

Een gebundelde afbeelding laden:

package com.example;

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

Standaardconfiguratie laden

Standaard configuratie-eigenschappen lezen:

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;
    }
}

Bron met dezelfde naam laden vanuit meerdere JAR's

Bron met hetzelfde pad en dezelfde naam kan voorkomen in meer dan één JAR-bestand op het klassepad. Veel voorkomende gevallen zijn middelen volgens een conventie of die deel uitmaken van een verpakkingsspecificatie. Voorbeelden van dergelijke middelen zijn

  • META-INF / MANIFEST.MF
  • META-INF / beans.xml (CDI Spec)
  • ServiceLoader-eigenschappen met implementatieproviders

Om toegang te krijgen tot al deze bronnen in verschillende potten, moet men een ClassLoader gebruiken, die hiervoor een methode heeft. De geretourneerde Enumeration kan eenvoudig worden omgezet in een List met behulp van een Collectiefunctie.

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

Bronnen zoeken en lezen met een classloader

Het laden van bronnen in Java omvat de volgende stappen:

  1. De Class of ClassLoader zoeken die de bron zal vinden.
  2. De bron vinden.
  3. De bytestream verkrijgen voor de bron.
  4. De bytestream lezen en verwerken.
  5. De bytestream sluiten.

De laatste drie stappen worden meestal uitgevoerd door de URL door te geven aan een bibliotheekmethode of constructor om de bron te laden. In dit geval gebruikt u meestal een methode getResource . Het is ook mogelijk om de brongegevens in de toepassingscode te lezen. In dit geval gebruikt u meestal getResourceAsStream .

Absolute en relatieve bronpaden

Bronnen die vanuit het classpath kunnen worden geladen, worden aangegeven met een pad . De syntaxis van het pad is vergelijkbaar met een UNIX / Linux-bestandspad. Het bestaat uit eenvoudige namen gescheiden door schuine streep ( / ) tekens. Een relatief pad begint met een naam en een absoluut pad begint met een scheidingsteken.

Zoals de Classpath-voorbeelden beschrijven, definieert een JVM's classpath een naamruimte door de naamruimten van de mappen en JAR- of ZIP-bestanden in het classpath te overlappen. Wanneer een absoluut pad is opgelost, interpreteren de classloaders de initiaal / als de root van de naamruimte. Een relatief pad kan daarentegen worden omgezet ten opzichte van elke "map" in de naamruimte. De gebruikte map is afhankelijk van het object dat u gebruikt om het pad op te lossen.

Een klasse of Classloader verkrijgen

Een resource kan worden gevonden met behulp van een Class object of een ClassLoader object. Een Class object kan relatieve paden oplossen, dus u gebruikt meestal een van deze als u een (class) relatieve resource hebt. Er zijn verschillende manieren om een Class object te verkrijgen. Bijvoorbeeld:

  • Een letterlijke klasse geeft u het Class object voor elke klasse die u in Java-broncode kunt noemen; bijv. String.class geeft u het Class object voor het String type.

  • Object.getClass() geeft u het Class object voor het type od elk object; bijv. "hello".getClass() is een andere manier om Class van het String type te krijgen.

  • De methode Class.forName(String) laadt (indien nodig) een klasse dynamisch en retourneert het Class object; bijv. Class.forName("java.lang.String") .

Een ClassLoader object wordt meestal verkregen door getClassLoader() aan te roepen op een Class object. Het is ook mogelijk om de standaardklasse- ClassLoader.getSystemClassLoader() van de JVM te verkrijgen met behulp van de statische methode ClassLoader.getSystemClassLoader() .

De get methoden

Zodra u een instantie Class of ClassLoader hebt, kunt u een bron vinden op een van de volgende manieren:

methoden Beschrijving
ClassLoader.getResource(path)
ClassLoader.getResources(path)
Retourneert een URL die de locatie van de resource met het opgegeven pad vertegenwoordigt.
ClassLoader.getResources(path)
Class.getResources(path)
Retourneert een Enumeration<URL> met de URL's die kunnen worden gebruikt om de bron foo.bar te vinden; zie hieronder.
ClassLoader.getResourceAsStream(path)
Class.getResourceStream(path)
Retourneert een InputStream waaruit u de inhoud van de bron foo.bar kunt lezen als een reeks bytes.

Opmerkingen:

  • Het belangrijkste verschil tussen de ClassLoader en Class versies van de methoden is dat relatieve paden worden geïnterpreteerd.

    • Met de Class methoden wordt een relatief pad in de "map" opgelost dat overeenkomt met het klassenpakket.
    • De ClassLoader methoden behandelen relatieve paden alsof ze absoluut zijn; dat wil zeggen het oplossen ervan in de "hoofdmap" van de classpath-naamruimte.
  • Als de gevraagde resource (of resources) niet kunnen worden gevonden, retourneren de methods return getResource en getResourceAsStream null , and the retourneren de methods return an empty getResources methods return an empty Enumeratie`.

  • De geretourneerde URL's kunnen worden URL.toStream() met URL.toStream() . Dit kunnen file: URL's of andere conventionele URL's zijn, maar als de bron zich in een JAR-bestand bevindt, zijn dit jar: URL's die het JAR-bestand en een specifieke bron erin identificeren.

  • Als uw code een methode getResourceAsStream (of URL.toStream() ) gebruikt om een InputStream te verkrijgen, is deze verantwoordelijk voor het afsluiten van het stream-object. Als de stroom niet wordt afgesloten, kan er een bronlek optreden.



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow