Es gibt subtile Unterschiede, wie das, was fileName
Sie passieren, interpretiert wird. Grundsätzlich haben Sie zwei verschiedene Methoden: ClassLoader.getResourceAsStream()
undClass.getResourceAsStream()
. Diese beiden Methoden lokalisieren die Ressource unterschiedlich.
In Class.getResourceAsStream(path)
wird der Pfad als lokaler Pfad für das Paket der Klasse interpretiert, von der aus Sie ihn aufrufen. Wenn Sie beispielsweise aufrufen, String.getResourceAsStream("myfile.txt")
suchen Sie in Ihrem Klassenpfad am folgenden Speicherort nach einer Datei : "java/lang/myfile.txt"
. Wenn Ihr Pfad mit a beginnt /
, wird er als absoluter Pfad betrachtet und beginnt mit der Suche im Stammverzeichnis des Klassenpfads. Wenn Sie anrufen, String.getResourceAsStream("/myfile.txt")
wird der folgende Ort in Ihrem Klassenpfad angezeigt ./myfile.txt
.
ClassLoader.getResourceAsStream(path)
betrachtet alle Pfade als absolute Pfade. Rufen Sie also an String.getClassLoader().getResourceAsStream("myfile.txt")
und String.getClassLoader().getResourceAsStream("/myfile.txt")
suchen beide nach einer Datei in Ihrem Klassenpfad an folgendem Speicherort : ./myfile.txt
.
Jedes Mal, wenn ich in diesem Beitrag einen Speicherort erwähne, kann dies ein Speicherort in Ihrem Dateisystem selbst oder in der entsprechenden JAR-Datei sein, abhängig von der Klasse und / oder dem ClassLoader, aus dem Sie die Ressource laden.
In Ihrem Fall laden Sie die Klasse von einem Anwendungsserver, daher sollten Sie Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName)
stattdessen verwenden this.getClass().getClassLoader().getResourceAsStream(fileName)
. this.getClass().getResourceAsStream()
wird auch funktionieren.
In diesem Artikel finden Sie detailliertere Informationen zu diesem bestimmten Problem.
Warnung für Benutzer von Tomcat 7 und niedriger
Eine der Antworten auf diese Frage besagt, dass meine Erklärung für Tomcat 7 falsch zu sein scheint. Ich habe versucht, mich umzuschauen, um herauszufinden, warum dies der Fall ist.
Daher habe ich mir den Quellcode von Tomcat WebAppClassLoader
für mehrere Versionen von Tomcat angesehen. Die Implementierung von findResource(String name)
(die maßgeblich für die Erstellung der URL zur angeforderten Ressource verantwortlich ist) ist in Tomcat 6 und Tomcat 7 praktisch identisch, in Tomcat 8 jedoch unterschiedlich.
In den Versionen 6 und 7 versucht die Implementierung nicht, den Ressourcennamen zu normalisieren. Dies bedeutet, dass in diesen Versionen classLoader.getResourceAsStream("/resource.txt")
möglicherweise nicht das gleiche Ergebnis wie beim classLoader.getResourceAsStream("resource.txt")
Ereignis erzielt wird (obwohl dies vom Javadoc angegeben wird). [Quellcode]
In Version 8 wird der Ressourcenname jedoch normalisiert, um sicherzustellen, dass die absolute Version des Ressourcennamens verwendet wird. Daher sollten in Tomcat 8 die beiden oben beschriebenen Aufrufe immer das gleiche Ergebnis liefern.[Quellcode]
Aus diesem Grund müssen Sie besonders vorsichtig sein, wenn Sie Tomcat-Versionen vor 8 verwenden ClassLoader.getResourceAsStream()
oder Class.getResourceAsStream()
verwenden. Außerdem müssen Sie berücksichtigen, dass class.getResourceAsStream("/resource.txt")
tatsächlich Anrufe getätigt werden classLoader.getResourceAsStream("resource.txt")
(der führende /
wird entfernt).
getClass().getResourceAsStream("/myfile.txt")
sich das anders verhält alsgetClassLoader().getResourceAsStream("/myfile.txt")
.