Различные способы загрузки файла в качестве входного потока


в чем разница между:

InputStream is = this.getClass().getClassLoader().getResourceAsStream(fileName)

и

InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName)

и

InputStream is = this.getClass().getResourceAsStream(fileName)

когда каждый из них более подходит для использования, чем другие?

файл, который я хочу прочитать это в classpath, как мой класс, который читает файл. Мой класс и файл находятся в одном jar и упакованы в файл EAR, а также развернуты в WebSphere 6.1.

6 190

6 ответов:

есть тонкие различия, как fileName вы проходите интерпретируется. В принципе, у вас есть 2 различных метода: ClassLoader.getResourceAsStream() и Class.getResourceAsStream(). Эти два метода будут находить ресурс по-разному.

In Class.getResourceAsStream(path), путь интерпретируется как локальный путь к пакету класса, из которого вы его вызываете. Например вызов,String.getResourceAsStream("myfile.txt") будет искать файл в classpath в следующем месте: "java/lang/myfile.txt". Если ваш путь начинается с /, тогда будет считается абсолютным путем, и начнется поиск от корня classpath. Так зовет String.getResourceAsStream("/myfile.txt") будет смотреть на следующее место в вашем пути к классу ./myfile.txt.

ClassLoader.getResourceAsStream(path) будет считать все пути абсолютными путями. Так зовет String.getClassLoader().getResourceAsStream("myfile.txt") и String.getClassLoader().getResourceAsStream("/myfile.txt") оба будут искать файл в вашем classpath в следующем месте:./myfile.txt.

каждый раз, когда я упоминаю место в этом посте, это может быть место в самой файловой системе или внутри соответствующий файл jar, в зависимости от класса и/или загрузчика классов, из которого вы загружаете ресурс.

в вашем случае вы загружаете класс с сервера приложений, поэтому вы должны использовать 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 in 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); 
  }
}

все эти ответы здесь, а также ответов в этот вопрос, предложите загрузить абсолютные URL-адреса, например " /foo / bar.свойства " обрабатывается то же самое с помощью 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: Я также разместил это здесь

после попытки некоторые способы загрузки файла без успеха, я вспомнил, что я мог бы использовать FileInputStream, которые прекрасно работали.

InputStream is = new FileInputStream("file.txt");

Это еще один способ прочитать файл в InputStream, он считывает файл из текущей папки.

это работает , попробуйте этот :

InputStream in_s1 =   TopBrandData.class.getResourceAsStream("/assets/TopBrands.xml");