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")
.getClassLoader()
vonString
, ist es ein Fehler , oder benötigen eine Erweiterung?Verwenden Sie
MyClass.class.getClassLoader().getResourceAsStream(path)
diese Option , um die mit Ihrem Code verknüpfte Ressource zu laden. Verwenden Sie diese OptionMyClass.class.getResourceAsStream(path)
als Verknüpfung und für Ressourcen, die im Paket Ihrer Klasse enthalten sind.Verwenden Sie
Thread.currentThread().getContextClassLoader().getResourceAsStream(path)
diese Option , um Ressourcen abzurufen, die Teil des Clientcodes sind und nicht eng an den aufrufenden Code gebunden sind. Sie sollten damit vorsichtig sein, da der Thread-Kontextklassenlader auf alles zeigen kann.quelle
Einfaches altes Java auf einfachem altem Java 7 und keine anderen Abhängigkeiten zeigen den Unterschied ...
Ich legte
file.txt
einc:\temp\
und legtec:\temp\
den Klassenpfad an.Es gibt nur einen Fall, in dem es einen Unterschied zwischen den beiden Anrufen gibt.
quelle
Alle diese Antworten hier sowie die Antworten in dieser Frage legen nahe, dass das Laden absoluter URLs wie "/foo/bar.properties" von
class.getResourceAsStream(String)
und gleich behandelt wirdclass.getClassLoader().getResourceAsStream(String)
. Dies ist NICHT der Fall, zumindest nicht in meiner Tomcat-Konfiguration / Version (derzeit 7.0.40).Entschuldigung, ich habe absolut keine befriedigende Erklärung, aber ich denke, dass Tomcat schmutzige Tricks und seine schwarze Magie mit den Klassenladern macht und den Unterschied verursacht. Ich habe es
class.getResourceAsStream(String)
in der Vergangenheit immer benutzt und hatte keine Probleme.PS: Ich stellte auch dies über hier
quelle
ClassLoader.getResourceAsStream()
als absolut? Dies ist plausibel, da, wie in einigen Kommentaren oben erwähnt,Class.getResourceAsStream
tatsächlich getClassLoader (). GetResourceAsStream` aufgerufen wird, aber jeder führende Schrägstrich entfernt wird.Class.getResourceAsStream()
undClassLoader.getResourceAsStream()
letztendlich AufrufClassLoader.findResource()
einer geschützten Methode, deren Standardimplementierung leer ist, deren Javadoc jedoch ausdrücklich angibt: "Klassenladeprogrammimplementierungen sollten diese Methode überschreiben, um anzugeben, wo Ressourcen finden ". Ich vermute, dass die Implementierung dieser speziellen Methode durch Tomcat fehlerhaft sein könnte.WebAppClassLoader.findResource(String name)
in Tomcat 7 mit dem von Tomcat 8 , und es scheint , dass es ein entscheidender Unterschied gibt. Tomcat 8 normalisiert den Ressourcennamen explizit, indem es einen führenden Namen hinzufügt,/
wenn dieser keinen enthält, wodurch alle Namen absolut werden. Tomcat 7 nicht. Das ist eindeutig ein Fehler in Tomcat 7Nachdem ich einige Möglichkeiten ausprobiert hatte, die Datei ohne Erfolg zu laden, erinnerte ich mich, dass ich sie verwenden konnte
FileInputStream
, was perfekt funktionierte.Dies ist eine weitere Möglichkeit, eine Datei in eine Datei einzulesen.
InputStream
Sie liest die Datei aus dem aktuell ausgeführten Ordner.quelle
Es funktioniert, probieren Sie Folgendes aus:
quelle