Существуют тонкие различия в том, как fileName
интерпретируется передаваемый вами текст. В принципе, у вас есть 2 разные методы: ClassLoader.getResourceAsStream()
иClass.getResourceAsStream()
. Эти два метода будут определять местоположение ресурса по-разному.
В Class.getResourceAsStream(path)
, путь интерпретируется как локальный путь к пакету класса, из которого вы вызываете его. Например , призванию, String.getResourceAsStream("myfile.txt")
будет искать файл в вашем пути к классам по следующему адресу: "java/lang/myfile.txt"
. Если ваш путь начинается с a /
, то он будет считаться абсолютным путем и начнет поиск с корня пути к классам. Таким образом, вызов String.getResourceAsStream("/myfile.txt")
будет смотреть на следующее место в вашем пути к классу ./myfile.txt
.
ClassLoader.getResourceAsStream(path)
будет считать все пути абсолютными. Так что вызов String.getClassLoader().getResourceAsStream("myfile.txt")
и String.getClassLoader().getResourceAsStream("/myfile.txt")
оба будут искать файл в вашем classpath в следующем месте:./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")
.getClassLoader()
изString
, это ошибка или необходимость расширения?Используйте
MyClass.class.getClassLoader().getResourceAsStream(path)
для загрузки ресурса, связанного с вашим кодом. ИспользуйтеMyClass.class.getResourceAsStream(path)
в качестве ярлыка и для ресурсов, упакованных в пакет вашего класса.Используется
Thread.currentThread().getContextClassLoader().getResourceAsStream(path)
для получения ресурсов, которые являются частью клиентского кода, а не тесно связаны с вызывающим кодом. Вы должны быть осторожны с этим, поскольку загрузчик класса контекста потока может указывать на что угодно.источник
Обычная старая Java на простой старой Java 7 и никаких других зависимостей демонстрирует разницу ...
Я положил
file.txt
вc:\temp\
и я поставилc:\temp\
на пути к классам.Существует только один случай, когда есть разница между двумя вызовами.
источник
Все эти ответы здесь, а также ответы в этом вопросе предполагают, что загрузка абсолютных URL-адресов, таких как "/foo/bar.properties", обрабатывается одинаково с помощью
class.getResourceAsStream(String)
иclass.getClassLoader().getResourceAsStream(String)
. Это НЕ так, по крайней мере, в моей конфигурации / версии Tomcat (в настоящее время 7.0.40).Извините, у меня нет абсолютно никакого удовлетворительного объяснения, но я предполагаю, что tomcat делает грязные трюки и свою черную магию с загрузчиками классов и вызывает разницу. Я всегда использовал
class.getResourceAsStream(String)
в прошлом и не было никаких проблем.PS: я также разместил это здесь
источник
ClassLoader.getResourceAsStream()
как абсолютные? Это правдоподобно, потому что, как упоминалось в некоторых комментариях выше, наClass.getResourceAsStream
самом деле вызывает getClassLoader (). GetResourceAsStream`, но удаляет любой начальный слеш.Class.getResourceAsStream()
и то, и другое, вClassLoader.getResourceAsStream()
конечном счете, вызов,ClassLoader.findResource()
который является защищенным методом, реализация по умолчанию которого пуста, но чей javadoc явно заявляет «Реализации загрузчика классов должны переопределить этот метод, чтобы указать, где найти ресурсы ". Я подозреваю, что реализация Tomcat этого конкретного метода может быть ошибочной.WebAppClassLoader.findResource(String name)
в Tomcat 7 с тем, что в Tomcat 8 , и кажется , что есть принципиальное различие. Tomcat 8 явно нормализует имя ресурса, добавляя ведущий,/
если он не содержит, что делает все имена абсолютными. Tomcat 7 нет. Это явно ошибка в Tomcat 7Попробовав несколько способов загрузить файл безуспешно, я вспомнил, что смог использовать
FileInputStream
, что сработало отлично.Это еще один способ прочитать файл в файл
InputStream
, он читает файл из текущей запущенной папки.источник
Это работает, попробуйте это:
источник