Различные способы загрузки файла в качестве InputStream
В чем разница между:
InputStream is = this.getClass().getClassLoader().getResourceAsStream(fileName)
а также
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName)
а также
InputStream is = this.getClass().getResourceAsStream(fileName)
Когда каждый из них более подходит для использования, чем другие?
Файл, который я хочу прочитать, находится в classpath как мой класс, который читает файл. Мой класс и файл находятся в одном банке, упакованы в файл EAR и развернуты в WebSphere 6.1.
6 ответов
Есть тонкие различия в том, как fileName
Вы проходите, интерпретируется. По сути, у вас есть 2 разных метода: ClassLoader.getResourceAsStream()
а также Class.getResourceAsStream()
, Эти два метода будут определять местоположение ресурса по-разному.
В Class.getResourceAsStream(path)
путь интерпретируется как локальный путь к пакету класса, из которого вы его вызываете. Например, позвонив, String.getResourceAsStream("myfile.txt")
будет искать файл в вашем classpath в следующем месте: "java/lang/myfile.txt"
, Если ваш путь начинается с /
, тогда он будет считаться абсолютным путем и начнет поиск из корня пути к классам. Так зовет 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")
(ведущий /
раздетый).
Использование MyClass.class.getClassLoader().getResourceAsStream(path)
загрузить ресурс, связанный с вашим кодом. использование MyClass.class.getResourceAsStream(path)
как ярлык, и для ресурсов, упакованных в пакет вашего класса.
использование Thread.currentThread().getContextClassLoader().getResourceAsStream(path)
чтобы получить ресурсы, которые являются частью клиентского кода, а не тесно связаны с вызывающим кодом. Вы должны быть осторожны с этим, поскольку загрузчик класса контекста потока может указывать на что угодно.
Обычная старая Java на простой старой Java 7 и никаких других зависимостей демонстрирует разницу...
я кладу file.txt
в c:\temp\
и я положил c:\temp\
на пути к классам.
Существует только один случай, когда есть разница между двумя вызовами.
class J {
public static void main(String[] a) {
// as "absolute"
// ok
System.err.println(J.class.getResourceAsStream("/file.txt") != null);
// pop
System.err.println(J.class.getClassLoader().getResourceAsStream("/file.txt") != null);
// as relative
// ok
System.err.println(J.class.getResourceAsStream("./file.txt") != null);
// ok
System.err.println(J.class.getClassLoader().getResourceAsStream("./file.txt") != null);
// no path
// ok
System.err.println(J.class.getResourceAsStream("file.txt") != null);
// ok
System.err.println(J.class.getClassLoader().getResourceAsStream("file.txt") != null);
}
}
Попробовав несколько способов загрузить файл безуспешно, я вспомнил, что могу использовать FileInputStream
, который работал отлично.
InputStream is = new FileInputStream("file.txt");
Это еще один способ прочитать файл в InputStream
, он читает файл из текущей запущенной папки.
Все эти ответы здесь, а также ответы в этом вопросе предполагают, что загрузка абсолютных URL, таких как "/foo/bar.properties", обрабатывается одинаково class.getResourceAsStream(String)
а также class.getClassLoader().getResourceAsStream(String)
, Это НЕ так, по крайней мере, в моей конфигурации / версии Tomcat (в настоящее время 7.0.40).
MyClass.class.getResourceAsStream("/foo/bar.properties"); // works!
MyClass.class.getClassLoader().getResourceAsStream("/foo/bar.properties"); // does NOT work!
Извините, у меня нет абсолютно никакого удовлетворительного объяснения, но я предполагаю, что tomcat делает грязные трюки и свою черную магию с загрузчиками классов и вызывает разницу. Я всегда использовал class.getResourceAsStream(String)
в прошлом и не было никаких проблем.
PS: я также разместил это здесь
Это работает, попробуйте это:
InputStream in_s1 = TopBrandData.class.getResourceAsStream("/assets/TopBrands.xml");