Il existe des différences subtiles quant à la façon dont fileName
vous passez est interprété. Fondamentalement, vous avez 2 méthodes différentes: ClassLoader.getResourceAsStream()
etClass.getResourceAsStream()
. Ces deux méthodes localiseront la ressource différemment.
Dans Class.getResourceAsStream(path)
, le chemin d'accès est interprété comme un chemin d'accès local au package de la classe à partir de laquelle vous l'appelez. Par exemple appel, String.getResourceAsStream("myfile.txt")
va chercher un fichier dans votre classpath à l'adresse suivante: "java/lang/myfile.txt"
. Si votre chemin commence par un /
, il sera alors considéré comme un chemin absolu et commencera la recherche à partir de la racine du chemin de classe. Ainsi, l'appel String.getResourceAsStream("/myfile.txt")
se penchera sur l'emplacement suivant dans votre chemin de classe ./myfile.txt
.
ClassLoader.getResourceAsStream(path)
considérera tous les chemins comme des chemins absolus. Donc , appeler String.getClassLoader().getResourceAsStream("myfile.txt")
et String.getClassLoader().getResourceAsStream("/myfile.txt")
sera à la fois regarder un fichier dans votre classpath à l'adresse suivante: ./myfile.txt
.
Chaque fois que je mentionne un emplacement dans cet article, il peut s'agir d'un emplacement dans votre système de fichiers lui-même, ou à l'intérieur du fichier jar correspondant, en fonction de la classe et / ou du ClassLoader à partir desquels vous chargez la ressource.
Dans votre cas, vous chargez la classe à partir d'un serveur d'applications, vous devez donc l'utiliser à la Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName)
place de this.getClass().getClassLoader().getResourceAsStream(fileName)
. this.getClass().getResourceAsStream()
fonctionnera également.
Lisez cet article pour des informations plus détaillées sur ce problème particulier.
Avertissement pour les utilisateurs de Tomcat 7 et inférieurs
L'une des réponses à cette question indique que mon explication semble incorrecte pour Tomcat 7. J'ai essayé de regarder autour de moi pour voir pourquoi ce serait le cas.
J'ai donc regardé le code source de Tomcat WebAppClassLoader
pour plusieurs versions de Tomcat. L'implémentation de findResource(String name)
(qui est ultimement responsable de la production de l'URL de la ressource demandée) est pratiquement identique dans Tomcat 6 et Tomcat 7, mais est différente dans Tomcat 8.
Dans les versions 6 et 7, l'implémentation n'essaie pas de normaliser le nom de la ressource. Cela signifie que dans ces versions, il se classLoader.getResourceAsStream("/resource.txt")
peut qu'il ne produise pas le même résultat que l' classLoader.getResourceAsStream("resource.txt")
événement (car c'est ce que spécifie le Javadoc). [code source]
Cependant, dans la version 8, le nom de la ressource est normalisé pour garantir que la version absolue du nom de la ressource est celle utilisée. Par conséquent, dans Tomcat 8, les deux appels décrits ci-dessus doivent toujours renvoyer le même résultat. [code source]
Par conséquent, vous devez être extrêmement prudent lorsque vous utilisez ClassLoader.getResourceAsStream()
ou Class.getResourceAsStream()
sur des versions de Tomcat antérieures à 8. Et vous devez également garder à l'esprit que les class.getResourceAsStream("/resource.txt")
appels sont réellement effectués classLoader.getResourceAsStream("resource.txt")
(le début /
est supprimé).
getClass().getResourceAsStream("/myfile.txt")
se comporte différemment degetClassLoader().getResourceAsStream("/myfile.txt")
.getClassLoader()
deString
, est - ce une erreur ou besoin d' une extension?Utilisez
MyClass.class.getClassLoader().getResourceAsStream(path)
pour charger la ressource associée à votre code. UtilisationMyClass.class.getResourceAsStream(path)
comme raccourci et pour les ressources regroupées dans le package de votre classe.À utiliser
Thread.currentThread().getContextClassLoader().getResourceAsStream(path)
pour obtenir des ressources qui font partie du code client, et non pas étroitement liées au code appelant. Vous devez être prudent avec cela car le chargeur de classe de contexte de thread peut pointer vers n'importe quoi.la source
Plain old Java on plain old Java 7 et aucune autre dépendance ne démontre la différence ...
Je mets
file.txt
enc:\temp\
et je metsc:\temp\
sur le chemin de classe.Il n'y a qu'un seul cas où il y a une différence entre les deux appels.
la source
Toutes ces réponses ici, ainsi que les réponses à cette question , suggèrent que le chargement des URL absolues, comme "/foo/bar.properties", était traité de la même manière par
class.getResourceAsStream(String)
etclass.getClassLoader().getResourceAsStream(String)
. Ce n'est PAS le cas, du moins pas dans ma configuration / version Tomcat (actuellement 7.0.40).Désolé, je n'ai absolument aucune explication satisfaisante, mais je suppose que Tomcat fait des tours sales et sa magie noire avec les chargeurs de classe et cause la différence. J'ai toujours utilisé
class.getResourceAsStream(String)
dans le passé et je n'ai eu aucun problème.PS: j'ai aussi posté ça ici
la source
ClassLoader.getResourceAsStream()
comme absolus? Ceci est plausible car, comme mentionné dans certains commentaires ci-dessus,Class.getResourceAsStream
appelle en fait getClassLoader (). GetResourceAsStream` mais supprime toute barre oblique de début.Class.getResourceAsStream()
etClassLoader.getResourceAsStream()
finalement finir par appeler ceClassLoader.findResource()
qui est une méthode protégée dont la mise en œuvre par défaut est vide, mais dont javadoc déclare explicitement « implémentations de classe chargeur doivent remplacer cette méthode pour spécifier où trouver des ressources ". Je soupçonne que l'implémentation par tomcat de cette méthode particulière peut être défectueuse.WebAppClassLoader.findResource(String name)
dans Tomcat 7 avec celui de Tomcat 8 , et il semble qu'il ya une différence essentielle. Tomcat 8 normalise explicitement le nom de la ressource en ajoutant un interligne/
s'il n'en contient pas, ce qui rend tous les noms absolus. Tomcat 7 ne le fait pas. C'est clairement un bug dans Tomcat 7Après avoir essayé quelques façons de charger le fichier sans succès, je me suis souvenu que je pouvais l'utiliser
FileInputStream
, ce qui fonctionnait parfaitement.C'est une autre façon de lire un fichier dans un
InputStream
, il lit le fichier à partir du dossier en cours d'exécution.la source
Ça marche, essayez ceci:
la source