Istnieją subtelne różnice w fileName
interpretacji tego, co mijasz. Zasadniczo masz 2 różne metody: ClassLoader.getResourceAsStream()
i Class.getResourceAsStream()
. Te dwie metody będą lokalizować zasób inaczej.
W Class.getResourceAsStream(path)
, ścieżka jest interpretowana jako lokalna ścieżka do pakietu klasy, z której ją wywołujesz. Na przykład powołania, String.getResourceAsStream("myfile.txt")
będzie szukał pliku w ścieżce klas w następującej lokalizacji: "java/lang/myfile.txt"
. Jeśli twoja ścieżka zaczyna się od a /
, zostanie uznana za ścieżkę bezwzględną i rozpocznie wyszukiwanie od źródła ścieżki klasy. W ten sposób wywołanie String.getResourceAsStream("/myfile.txt")
obejrzy następującą lokalizację na ścieżce zajęć ./myfile.txt
.
ClassLoader.getResourceAsStream(path)
weźmie wszystkie ścieżki za ścieżki absolutne. Więc dzwoni String.getClassLoader().getResourceAsStream("myfile.txt")
i String.getClassLoader().getResourceAsStream("/myfile.txt")
będzie zarówno wygląd pliku w ścieżce klas w następującej lokalizacji: ./myfile.txt
.
Za każdym razem, gdy wspominam o lokalizacji w tym poście, może to być lokalizacja w twoim systemie plików lub wewnątrz odpowiedniego pliku jar, w zależności od Class i / lub ClassLoadera, z którego ładujesz zasób.
W twoim przypadku ładujesz klasę z serwera aplikacji, więc powinieneś użyć Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName)
zamiast this.getClass().getClassLoader().getResourceAsStream(fileName)
. this.getClass().getResourceAsStream()
będzie również działać.
Przeczytaj ten artykuł, aby uzyskać bardziej szczegółowe informacje na temat tego konkretnego problemu.
Ostrzeżenie dla użytkowników Tomcat 7 i niższych
Jedna z odpowiedzi na to pytanie mówi, że moje wyjaśnienie wydaje się niepoprawne w przypadku Tomcat 7. Próbowałem się rozejrzeć, aby zobaczyć, dlaczego tak się dzieje.
Więc spojrzałem na kod źródłowy Tomcata WebAppClassLoader
dla kilku wersji Tomcata. Implementacja findResource(String name)
(która jest całkowicie odpowiedzialna za tworzenie adresu URL do żądanego zasobu) jest praktycznie identyczna w Tomcat 6 i Tomcat 7, ale jest inna w Tomcat 8.
W wersjach 6 i 7 implementacja nie próbuje znormalizować nazwy zasobu. Oznacza to, że w tych wersjach classLoader.getResourceAsStream("/resource.txt")
może nie dawać tego samego wyniku co classLoader.getResourceAsStream("resource.txt")
zdarzenie, chociaż powinno (ponieważ tak określa Javadoc). [kod źródłowy]
Jednak w wersji 8 nazwa zasobu jest znormalizowana, aby zagwarantować, że używana jest bezwzględna wersja nazwy zasobu. Dlatego w Tomcat 8 dwa opisane powyżej połączenia powinny zawsze zwracać ten sam wynik. [kod źródłowy]
W rezultacie, trzeba być bardzo ostrożnym podczas korzystania ClassLoader.getResourceAsStream()
lub Class.getResourceAsStream()
w wersjach Tomcat wcześniej niż 8. I trzeba też pamiętać, że class.getResourceAsStream("/resource.txt")
faktycznie rozmowy classLoader.getResourceAsStream("resource.txt")
(wiodącym /
jest usuwany).
getClass().getResourceAsStream("/myfile.txt")
zachowuje się inaczej niżgetClassLoader().getResourceAsStream("/myfile.txt")
.