Czy istnieje interfejs API, aby uzyskać zasób ścieżki klas (np. Z tego, z czego otrzymam Class.getResource(String)
) jako plik java.nio.file.Path
? Idealnie, chciałbym używać nowych, fantazyjnych Path
API z zasobami classpath.
143
Paths.get(URI)
´URL.toURI (), and last
getResource () `, która zwraca plikURL
. Możesz połączyć je w łańcuch. Jednak nie próbowałem.Odpowiedzi:
Ten działa dla mnie:
źródło
Thread.currentThread().getContextClassLoader().getResource(resourceName).toURI()
Domyślam się, że to, co chcesz zrobić, to wywołanie Files.lines (...) na zasobie pochodzącym ze ścieżki klas - prawdopodobnie z słoika.
Ponieważ Oracle zagmatwało pojęcie, kiedy ścieżka jest ścieżką, nie zmuszając getResource do zwracania użytecznej ścieżki, jeśli znajduje się ona w pliku jar, musisz zrobić coś takiego:
źródło
class.getResource
znak „/”, nie wiem, ale w moim przypadku wymaga ukośnika, alegetSystemResourceAsStream
nie mogę znaleźć pliku poprzedzonego ukośnikiem.Najbardziej ogólne rozwiązanie jest następujące:
Główną przeszkodą jest poradzenie sobie z dwiema możliwościami, albo posiadanie istniejącego systemu plików, którego powinniśmy używać, ale nie zamykania (jak w przypadku
file
identyfikatorów URI lub pamięci modułów Java 9), albo konieczność samodzielnego otwierania, a tym samym bezpiecznego zamykania systemu plików (np. zip / jar).Dlatego powyższe rozwiązanie hermetyzuje rzeczywistą akcję w pliku
interface
, obsługuje oba przypadki, bezpiecznie zamykając później w drugim przypadku i działa od Java 7 do Java 10. Sprawdza, czy istnieje już otwarty system plików przed otwarciem nowego, więc działa również w przypadku, gdy inny składnik Twojej aplikacji już otworzył system plików dla tego samego pliku zip / jar.Można go używać we wszystkich wymienionych powyżej wersjach Java, np. Do wypisywania zawartości pakietu (
java.lang
w przykładzie) jakoPath
s, na przykład:W Javie 8 lub nowszym można używać wyrażeń lambda lub odwołań do metod, aby przedstawić rzeczywistą akcję, np
zrobić to samo.
Ostateczna wersja systemu modułów Java 9 zepsuła powyższy przykład kodu. JRE niekonsekwentnie zwraca ścieżkę
/java.base/java/lang/Object.class
dlaObject.class.getResource("Object.class")
podczas gdy powinno być/modules/java.base/java/lang/Object.class
. Można to naprawić, dodając brakującą wartość,/modules/
gdy ścieżka nadrzędna jest zgłaszana jako nieistniejąca:Następnie będzie ponownie działać ze wszystkimi wersjami i metodami przechowywania.
źródło
Okazuje się, że możesz to zrobić z pomocą wbudowanego dostawcy systemu plików Zip . Jednak przekazanie identyfikatora URI zasobu bezpośrednio do
Paths.get
nie zadziała; zamiast tego należy najpierw utworzyć system plików zip dla identyfikatora URI jar bez nazwy wpisu, a następnie odnieść się do wpisu w tym systemie plików:Aktualizacja:
Słusznie wskazano, że powyższy kod zawiera wyciek zasobów, ponieważ kod otwiera nowy obiekt FileSystem, ale nigdy go nie zamyka. Najlepszym podejściem jest przekazanie obiektu roboczego podobnego do Konsumenta, podobnie jak robi to odpowiedź Holgera. Otwórz system plików ZipFS na tyle długo, aby pracownik mógł zrobić wszystko, co musi zrobić ze ścieżką (o ile pracownik nie będzie próbował przechowywać obiektu ścieżki do późniejszego użycia), a następnie zamknij system plików.
źródło
newFileSystem
może prowadzić do tego, że wiele zasobów będzie pozostawać otwartych na zawsze. Chociaż dodatek @raisercostin pozwala uniknąć błędu podczas próby utworzenia już utworzonego systemu plików, jeśli spróbujesz użyć zwróconegoPath
, otrzymasz plikClosedFileSystemException
. Odpowiedź @Holger działa dobrze dla mnie.FileSystem
. Jeśli załadujesz zasób z słoika, a następnie utworzysz wymaganyFileSystem
-FileSystem
pozwoli ci to również załadować inne zasoby z tego samego słoika. Po utworzeniu nowegoFileSystem
zasobu możesz po prostu spróbować ponownie załadować zasób za pomocą,Paths.get(Path)
a implementacja automatycznie użyje nowegoFileSystem
.#getPath(String)
metody naFileSystem
obiekcie.Napisałem małą metodę pomocniczą do odczytu
Paths
z zasobów Twojej klasy. Jest to bardzo wygodne w użyciu, ponieważ wymaga jedynie odniesienia do klasy, w której przechowujesz zasoby, oraz nazwy samego zasobu.źródło
Nie można utworzyć identyfikatora URI z zasobów znajdujących się w pliku jar. Możesz po prostu zapisać go w pliku tymczasowym, a następnie użyć (java8):
źródło
Odczytaj plik z folderu zasobów za pomocą NIO, w java8
źródło
Musisz zdefiniować system plików, aby odczytywać zasoby z pliku jar, jak wspomniano w https://docs.oracle.com/javase/8/docs/technotes/guides/io/fsp/zipfilesystemprovider.html . Udało mi się odczytać zasób z pliku jar z poniższymi kodami:
źródło