Różne sposoby ładowania pliku jako strumienia wejściowego

Jaka jest różnica między:

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

I

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

I

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

Kiedy każdy z nich jest bardziej odpowiedni do użycia niż pozostałe?

Plik, który chcę odczytać znajduje się w ścieżce classpath jako moja klasa, która odczytuje plik. Moja klasa I Plik są w tym samym słoiku i spakowane do pliku EAR, i wdrożone w WebSphere 6.1.

Author: Buhake Sindi, 2009-03-24

6 answers

Istnieją subtelne różnice co do interpretacji fileName, które przechodzisz. Zasadniczo masz 2 różne metody: ClassLoader.getResourceAsStream() i Class.getResourceAsStream(). Te dwie metody zlokalizują zasób inaczej.

W Class.getResourceAsStream(path), ścieżka jest interpretowana jako ścieżka lokalna do pakietu klasy, z której go wywołujesz. Na przykład wywołanie, String.getResourceAsStream("myfile.txt") będzie szukać pliku w twojej ścieżce klasowej w następującej lokalizacji: "java/lang/myfile.txt". Jeśli ścieżka zaczyna się od /, to będzie traktowana jako ścieżka bezwzględna, i rozpocznie wyszukiwanie z katalogu głównego ścieżki klasowej. Tak więc wywołanie String.getResourceAsStream("/myfile.txt") spojrzy na następujące miejsce w twojej ścieżce klasowej ./myfile.txt.

ClassLoader.getResourceAsStream(path) rozważy wszystkie ścieżki jako ścieżki absolutne. Wywołanie String.getClassLoader().getResourceAsStream("myfile.txt") i String.getClassLoader().getResourceAsStream("/myfile.txt") spowoduje, że obie strony będą szukać pliku w twojej ścieżce klasowej 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 samym systemie plików lub wewnątrz odpowiedniego pliku jar, w zależności od klasy i / lub Classloadera ładujesz zasób z.

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ł {[37] } aby uzyskać bardziej szczegółowe informacje na temat tego konkretnego problemu.


Ostrzeżenie dla użytkowników Tomcat 7 i poniżej

Jedna z odpowiedzi na to pytanie stwierdza, że moje wyjaśnienie wydaje się być nieprawidłowe Dla Tomcat 7. Próbowałem się rozejrzeć, żeby zobaczyć, dlaczego tak by było.

Więc spojrzałem na kod źródłowy Tomcat WebAppClassLoader dla kilku wersji Tomcat. Implementacja findResource(String name) (która jest utimately 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 dać tego samego wyniku Co classLoader.getResourceAsStream("resource.txt") event chociaż powinien (ponieważ to co określa Javadoc). [kod źródłowy]

W wersji 8 nazwa zasobu jest znormalizowana, aby zagwarantować, że bezwzględna wersja nazwy zasobu jest tą, która jest używana. Dlatego w Tomcat 8, dwa wywołania opisane powyżej powinny zawsze zwracać ten sam wynik. [kod źródłowy]

W związku z tym należy zachować szczególną ostrożność podczas używania ClassLoader.getResourceAsStream() lub Class.getResourceAsStream() w wersjach Tomcat wcześniejszych niż 8. I musisz również zachować należy pamiętać, że {[22] } faktycznie wywołuje classLoader.getResourceAsStream("resource.txt") (początek / jest pozbawiony).

 266
Author: LordOfThePigs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-26 16:07:52

Użyj MyClass.class.getClassLoader().getResourceAsStream(path), aby załadować zasoby związane z Twoim kodem. Użyj MyClass.class.getResourceAsStream(path) jako skrótu i dla zasobów spakowanych w pakiecie twojej klasy.

Użyj Thread.currentThread().getContextClassLoader().getResourceAsStream(path), aby uzyskać zasoby, które są częścią kodu klienta, a nie ściśle ograniczają się do kodu wywołującego. Powinieneś być z tym ostrożny, ponieważ Klasa kontekstowa wątku może wskazywać na cokolwiek.

 16
Author: Tom Hawtin - tackline,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-24 11:57:39

Plain old Java na plain old Java 7 i żadne inne zależności Nie pokazują różnicy...

Umieszczam file.txt w c:\temp\ i umieszczam c:\temp\ na ścieżce klasowej.

Jest tylko jeden przypadek, w którym istnieje różnica między dwoma wywołaniami.

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); 
  }
}
 5
Author: John Lonergan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-04 11:36:31

Wszystkie odpowiedzi tutaj, jak również odpowiedzi w to pytanie , sugerują, że ładowanie bezwzględnych adresów URL, takich jak " / foo / bar.właściwości " traktowane tak samo przez class.getResourceAsStream(String) i class.getClassLoader().getResourceAsStream(String). Tak nie jest, przynajmniej nie w mojej konfiguracji/wersji Tomcat (obecnie 7.0.40).

MyClass.class.getResourceAsStream("/foo/bar.properties"); // works!  
MyClass.class.getClassLoader().getResourceAsStream("/foo/bar.properties"); // does NOT work!

Przepraszam, nie mam absolutnie satysfakcjonującego wyjaśnienia, ale myślę, że tomcat robi brudne sztuczki i swoją czarną magię z klasą i powoduje różnicę. Zawsze używałem class.getResourceAsStream(String) w przeszłości i nie miałem żadnych problemów.

PS: zamieściłem to również nad tutaj

 2
Author: Tim Büthe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:26

Po wypróbowaniu kilku sposobów ładowania pliku bez powodzenia, przypomniałem sobie, że mogę użyć FileInputStream, co działało idealnie.

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

Jest to inny sposób odczytu pliku do InputStream, odczytuje on Plik z aktualnie uruchomionego folderu.

 -1
Author: Toni Almeida,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-20 15:03:51

To działa, wypróbuj to:

InputStream in_s1 =   TopBrandData.class.getResourceAsStream("/assets/TopBrands.xml");
 -3
Author: Jaspreet Singh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-29 15:12:26