J'aimerais connaître la meilleure façon de charger une ressource en Java:
this.getClass().getResource() (or getResourceAsStream())
,Thread.currentThread().getContextClassLoader().getResource(name)
,System.class.getResource(name)
.
J'aimerais connaître la meilleure façon de charger une ressource en Java:
this.getClass().getResource() (or getResourceAsStream())
,Thread.currentThread().getContextClassLoader().getResource(name)
,System.class.getResource(name)
.Réponses:
Trouvez la solution selon ce que vous voulez ...
Il y a deux choses que getResource
/ getResourceAsStream()
obtiendra de la classe sur laquelle elle est appelée ...
Donc si tu fais
this.getClass().getResource("foo.txt");
il tentera de charger foo.txt à partir du même paquet 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 classe de "this" et depuis le package xyz (il devra être 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 selon aucun package (il doit être absolument référencé)
System.class.getResource(name)
Chargera la ressource avec le chargeur de classe système (il devrait également être absolument référencé, car vous ne pourrez rien mettre dans le package java.lang (le package de System).
Jetez un œil à la source. Indique également que getResourceAsStream appelle simplement "openStream" sur l'URL renvoyée par getResource et la renvoie.
Thread#setContextClassLoader
. Ceci est utile si vous devez modifier le chemin d'accès aux classes pendant l'exécution du programme.
Eh bien, 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 vous soyez SuperClass
dans A.jar et SubClass
dans B.jar, et que vous exécutiez 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 l'utilisez, this.getClass().getResource()
il semblera relatif à SubClass
, dans B.jar. Je soupçonne que ce n'est généralement pas ce qui est requis.
Personnellement, j'utiliserais probablement le Foo.class.getResourceAsStream(name)
plus souvent - si vous connaissez déjà le nom de la ressource que vous recherchez, et que vous êtes sûr de son emplacement par rapport à Foo
, c'est la façon la plus robuste de le faire IMO.
Bien sûr, il y a des moments où ce n'est pas ce que vous voulez aussi: juger chaque cas selon ses mérites. C'est juste le "Je sais que cette ressource est fournie avec cette classe" est le plus courant que j'ai rencontré.
this.getClass()
. Créez une instance de la sous-classe et appelez la méthode ... elle affichera le nom de la sous-classe, pas la superclasse.
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);
}
Je sais qu'il est vraiment 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 seulement le 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;
}
}
J'ai essayé de nombreuses méthodes et fonctions suggérées ci-dessus, mais elles n'ont 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();
}
this.getClass().getResourceAsStream()
dans ce cas. Si vous jetez un œil à la source de la getResourceAsStream
méthode, vous remarquerez qu'elle fait la même chose que vous mais de manière plus intelligente (repli si aucun ne ClassLoader
peut être trouvé sur la classe). Il indique également que vous pouvez rencontrer un potentiel null
sur getClassLoader
votre code ...
this.getClass().getResourceAsStream()
ne fonctionne pas pour moi, donc j'utilise cela fonctionne. Je pense que certaines personnes peuvent faire face à des problèmes comme le mien.