Існують тонкі відмінності щодо того, як fileName
інтерпретується ваш передач. В основному у вас є два різні методи: ClassLoader.getResourceAsStream()
і Class.getResourceAsStream()
. Ці два методи по-різному знайдуть ресурс.
В Class.getResourceAsStream(path)
, шлях трактується як локальний шлях до пакету класу, з якого ви викликаєте. Наприклад , покликанням, String.getResourceAsStream("myfile.txt")
буде шукати файл у вашому шляху до класів за наступною адресою: "java/lang/myfile.txt"
. Якщо ваш шлях починається з значка a /
, він вважатиметься абсолютним шляхом і почне пошук з кореня classpath. Таким чином, дзвінок String.getResourceAsStream("/myfile.txt")
буде розглядати наступне місце на шляху вашого класу ./myfile.txt
.
ClassLoader.getResourceAsStream(path)
вважатиме всі шляхи абсолютними. Так виклику String.getClassLoader().getResourceAsStream("myfile.txt")
і String.getClassLoader().getResourceAsStream("/myfile.txt")
обидва будуть шукати файл у вашому шляху до класів за наступною адресою: ./myfile.txt
.
Кожен раз, коли я згадую про місце у цій публікації, це може бути місце у вашій файловій системі або у відповідному файлі jar, залежно від класу та / або ClassLoader, з якого ви завантажуєте ресурс.
У вашому випадку ви завантажуєте клас із сервера прикладних програм, тому його слід використовувати Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName)
замість this.getClass().getClassLoader().getResourceAsStream(fileName)
. this.getClass().getResourceAsStream()
також буде працювати.
Прочитайте цю статтю для отримання більш детальної інформації про цю конкретну проблему.
Попередження для користувачів Tomcat 7 і нижче
В одній з відповідей на це запитання вказується, що моє пояснення видається невірним для Tomcat 7. Я намагався озирнутися, щоб зрозуміти, чому це було так.
Тому я переглянув вихідний код Tomcat WebAppClassLoader
для декількох версій Tomcat. Реалізація findResource(String name)
(яка абсолютно відповідає за створення URL-адреси запитуваного ресурсу) практично однакова у Tomcat 6 та Tomcat 7, але відрізняється в Tomcat 8.
У версіях 6 і 7 реалізація не намагається нормалізувати ім'я ресурсу. Це означає, що в цих версіях він classLoader.getResourceAsStream("/resource.txt")
може не давати такого ж результату, що і classLoader.getResourceAsStream("resource.txt")
подія (хоча саме те, що вказує Javadoc). [вихідний код]
Однак у версії 8 ім'я ресурсу нормалізується, щоб гарантувати, що абсолютна версія імені ресурсу є тією, що використовується. Тому в Tomcat 8 два описані вище дзвінки завжди повинні повертати однаковий результат. [вихідний код]
Як результат, ви повинні бути особливо обережними при використанні ClassLoader.getResourceAsStream()
або Class.getResourceAsStream()
на версіях Tomcat раніше, ніж 8. І ви також повинні мати на увазі, що class.getResourceAsStream("/resource.txt")
насправді дзвонить classLoader.getResourceAsStream("resource.txt")
(ведучий /
позбавлений).
getClass().getResourceAsStream("/myfile.txt")
поводиться інакшеgetClassLoader().getResourceAsStream("/myfile.txt")
.