web-dev-qa-db-fra.com

Mode de chargement préféré des ressources dans Java

J'aimerais connaître le meilleur moyen de charger une ressource en Java:

  • this.getClass().getResource() (or getResourceAsStream()),
  • Thread.currentThread().getContextClassLoader().getResource(name),
  • System.class.getResource(name).
98
PomCompot

Élaborez la solution selon ce que vous voulez ...

Il y a deux choses que getResource/getResourceAsStream() obtiendra de la classe à laquelle elle est appelée ...

  1. Le chargeur de classe
  2. Le lieu de départ

Donc si tu le fais

this.getClass().getResource("foo.txt");

il tentera de charger foo.txt à partir du même package que la classe "this" et avec le chargeur de classe de la classe "this". Si vous mettez un "/" devant, vous faites absolument référence à la ressource.

this.getClass().getResource("/x/y/z/foo.txt")

chargera la ressource depuis le chargeur de classes de "this" et depuis le package x.y.z (il devra figurer dans le même répertoire que les classes de ce package).

Thread.currentThread().getContextClassLoader().getResource(name)

se chargera avec le chargeur de classe de contexte mais ne résoudra pas le nom en fonction d'un paquet (il doit être absolument référencé)

System.class.getResource(name)

Va charger la ressource avec le chargeur de classes du système (il faudrait aussi qu'il soit absolument référencé, car vous ne pourrez rien mettre dans le package Java.lang (le package de System).

Il suffit de regarder la source. Indique également que getResourceAsStream appelle simplement "openStream" sur l'URL renvoyée par getResource et le renvoie.

130
Michael Wiles

Cela dépend en partie de ce que vous voulez qu'il se passe si vous êtes réellement dans une classe dérivée.

Par exemple, supposons que SuperClass soit dans A.jar et que SubClass soit dans B.jar, et que vous exécutez du code dans une méthode d'instance déclarée dans SuperClass mais où this fait référence à une instance de SubClass. Si vous utilisez this.getClass().getResource(), il semblera relatif à SubClass, dans B.jar. Je soupçonne que c'est habituellement pas ce qui est requis.

Personnellement, j'utiliserais probablement Foo.class.getResourceAsStream(name) le plus souvent - si vous connaissez déjà le nom de la ressource que vous recherchez et que vous êtes certain de sa relation avec Foo, il s'agit du manière la plus robuste de le faire IMO.

Bien sûr, il y a des moments où c'est et non pas ce que vous voulez, aussi: jugez chaque affaire sur son mérite. "Je sais que cette ressource est fournie avec cette classe" est la plus courante que j'ai rencontrée.

13
Jon Skeet

Je recherche trois endroits comme indiqué ci-dessous. Commentaires bienvenus.

public URL getResource(String resource){

    URL url ;

    //Try with the Thread Context Loader. 
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    if(classLoader != null){
        url = classLoader.getResource(resource);
        if(url != null){
            return url;
        }
    }

    //Let's now try with the classloader that loaded this class.
    classLoader = Loader.class.getClassLoader();
    if(classLoader != null){
        url = classLoader.getResource(resource);
        if(url != null){
            return url;
        }
    }

    //Last ditch attempt. Get the resource from the classpath.
    return ClassLoader.getSystemResource(resource);
}
9
dogbane

Je sais que c'est très tard pour une autre réponse mais je voulais juste partager ce qui m'a aidé à la fin. Il chargera également les ressources/fichiers à partir du chemin absolu du système de fichiers (pas uniquement celui du chemin de classe).

public class ResourceLoader {

    public static URL getResource(String resource) {
        final List<ClassLoader> classLoaders = new ArrayList<ClassLoader>();
        classLoaders.add(Thread.currentThread().getContextClassLoader());
        classLoaders.add(ResourceLoader.class.getClassLoader());

        for (ClassLoader classLoader : classLoaders) {
            final URL url = getResourceWith(classLoader, resource);
            if (url != null) {
                return url;
            }
        }

        final URL systemResource = ClassLoader.getSystemResource(resource);
        if (systemResource != null) {
            return systemResource;
        } else {
            try {
                return new File(resource).toURI().toURL();
            } catch (MalformedURLException e) {
                return null;
            }
        }
    }

    private static URL getResourceWith(ClassLoader classLoader, String resource) {
        if (classLoader != null) {
            return classLoader.getResource(resource);
        }
        return null;
    }

}
3
nyxz

J'ai essayé beaucoup de manières et de fonctions suggérées ci-dessus, mais cela n'a pas fonctionné dans mon projet. Quoi qu'il en soit, j'ai trouvé une solution et la voici:

try {
    InputStream path = this.getClass().getClassLoader().getResourceAsStream("img/left-hand.png");
    img = ImageIO.read(path);
} catch (IOException e) {
    e.printStackTrace();
}
0
Vladislav