Czy istnieje interfejs API, aby uzyskać zasoby klasy classpath (np. Co otrzymam z Class.getResource(String)
) jako java.nio.file.Path
? Idealnie, chciałbym użyć nowych, fantazyjnych API Path z zasobami classpath.java.nio.file.Path dla zasobu classpath
Odpowiedz
Ten działa dla mnie:
return Paths.get(ClassLoader.getSystemResource(resourceName).toURI());
Nie będzie działać z zasobami w plikach .jar. – VGR
@VGR, jeśli zasoby w pliku .jar mogą wypróbować to '\t \t \t Zasób zasobów = nowy ClassPathResource (" usage.txt "); \t \t Czytnik buforów odczytu = nowy buforowany czytnik (nowy InputStreamReader (resource.getInputStream())); 'zobacz http://stackoverflow.com/questions/25869428/classpath-resource-not-found-when-running-as- jar – zhuguowei
Okazuje się, że możesz to zrobić, korzystając z wbudowanego Zip File System provider. Jednak przekazanie identyfikatora URI zasobu bezpośrednio do Paths.get
nie będzie działać; Zamiast tego, trzeba najpierw stworzyć system plików zip na jar URI bez nazwy wejścia, a następnie odwołać się do wpisu w tym systemie plików:
static Path resourceToPath(URL resource)
throws IOException,
URISyntaxException {
Objects.requireNonNull(resource, "Resource URL cannot be null");
URI uri = resource.toURI();
String scheme = uri.getScheme();
if (scheme.equals("file")) {
return Paths.get(uri);
}
if (!scheme.equals("jar")) {
throw new IllegalArgumentException("Cannot convert to Path: " + uri);
}
String s = uri.toString();
int separator = s.indexOf("!/");
String entryName = s.substring(separator + 2);
URI fileURI = URI.create(s.substring(0, separator));
FileSystem fs = FileSystems.newFileSystem(fileURI,
Collections.<String, Object>emptyMap());
return fs.getPath(entryName);
}
Uważaj na nowo utworzone fs. Drugie wywołanie używające tego samego słoika rzuci wyjątek narzekający na już istniejący system plików. Lepiej będzie wypróbować (FileSystem fs = ...) {return fs.getPath (entryName);} lub jeśli chcesz, aby ta pamięć podręczna była bardziej zaawansowana. W obecnej formie jest ryzykowne. – raisercostin
Poza kwestią potencjalnie niezamkniętego nowego systemu plików, założenia dotyczące związku między schematami i konieczności otwarcia nowego systemu plików oraz zagadki z zawartością URI ograniczają użyteczność rozwiązania. Skonfigurowałem [nową odpowiedź] (http://stackoverflow.com/a/36021165/2711488), która pokazuje ogólne podejście, które upraszcza działanie i obsługuje nowe schematy, takie jak nowe przechowywanie klasy Java 9 w tym samym czasie. Działa również wtedy, gdy ktoś inny w aplikacji już otworzył system plików (lub metoda jest wywoływana dwukrotnie dla tego samego słoika) ... – Holger
W zależności od zastosowania tego rozwiązania, niezamknięty 'newFileSystem' może prowadzić do wielu zasobów w zawieszeniu na zawsze. Chociaż @raisercostin addendum omija błąd podczas próby utworzenia już utworzonego systemu plików, jeśli spróbujesz użyć zwróconej 'Path', otrzymasz' ClosedFileSystemException'. Odpowiedź @Holger działa dobrze dla mnie. –
pisałem mała pomocnicza metoda odczytu Paths
z zasobów twojej klasy. Jest dość przydatny w użyciu, ponieważ wymaga jedynie odniesienia do klasy, w której przechowywane są twoje zasoby, jak również nazwy samego zasobu.
public static Path getResourcePath(Class<?> resourceClass, String resourceName) throws URISyntaxException {
URL url = resourceClass.getResource(resourceName);
return Paths.get(url.toURI());
}
Zgadywanie, że to, co chcesz zrobić, to wywołanie Files.lines (...) na zasobie pochodzącym ze ścieżki klas - prawdopodobnie z poziomu słoika.
Od Oracle zawiłe pojęcia kiedy ścieżka jest ścieżką, nie czyniąc getResource powrócić użytkowej ścieżkę, jeśli przebywa w pliku jar, co trzeba zrobić, to coś takiego:
Stream<String> stream = new BufferedReader(new InputStreamReader(ClassLoader.getSystemResourceAsStream("/filename.txt"))).lines();
, czy poprzedni "/" jest potrzebny w twoim przypadku, nie wiem, ale w moim przypadku 'class.getResource' wymaga ukośnika, ale' getSystemResourceAsStream' nie może znaleźć pliku po przedrostku z ukośnikiem. – Adam
You trzeba zdefiniować system plików do odczytu zasobu z pliku jar, jak wspomniano w https://docs.oracle.com/javase/8/docs/technotes/guides/io/fsp/zipfilesystemprovider.html. I sukces czytać zasobu z pliku jar z poniższych kodów:
Map<String, Object> env = new HashMap<>();
try (FileSystem fs = FileSystems.newFileSystem(uri, env)) {
Path path = fs.getPath("/path/myResource");
try (Stream<String> lines = Files.lines(path)) {
....
}
}
najbardziej ogólne rozwiązanie jest następujące:
interface IOConsumer<T> {
void accept(T t) throws IOException;
}
public static void processRessource(URI uri, IOConsumer<Path> action) throws IOException {
try {
Path p=Paths.get(uri);
action.accept(p);
}
catch(FileSystemNotFoundException ex) {
try(FileSystem fs = FileSystems.newFileSystem(
uri, Collections.<String,Object>emptyMap())) {
Path p = fs.provider().getPath(uri);
action.accept(p);
}
}
}
Główną przeszkodą jest do czynienia z dwoma możliwościami, albo mając istniejący system plików, który powinniśmy używać, ale nie w pobliżu (jak w przypadku URI z file
lub nadchodzącego modułu Java 9) lub konieczności otwarcia i bezpiecznego zamknięcia systemu plików (takich jak pliki zip/jar).
Dlatego powyższe rozwiązanie zawiera rzeczywistą akcję w interface
, obsługuje oba przypadki, następnie bezpiecznie zamyka się w drugim przypadku i działa z poziomu Java 7 do Javy 9. Sprawdza, czy istnieje już otwarty system plików przed otwarciem nowy, 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że być używany we wszystkich wymienionych wyżej wersjach Java, np. do wymieniający zawartość pakietu (java.lang
w przykładzie) jak Path
s, podobnie jak to:
processRessource(Object.class.getResource("Object.class").toURI(), new IOConsumer<Path>() {
public void accept(Path path) throws IOException {
try(DirectoryStream<Path> ds = Files.newDirectoryStream(path.getParent())) {
for(Path p: ds)
System.out.println(p);
}
}
});
Z Java 8 lub nowszej, można użyć wyrażeń lambda lub odniesienia metoda reprezentują rzeczywiste działania, na przykład
processRessource(Object.class.getResource("Object.class").toURI(), path -> {
try(Stream<Path> stream = Files.list(path.getParent())) {
stream.forEach(System.out::println);
}
});
zrobić to samo.
Ostateczne wydanie systemu modułu Java 9 spowodowało zerwanie powyższego przykładu kodu.JRE niekonsekwentnie zwraca ścieżkę /java.base/java/lang/Object.class
dla Object.class.getResource("Object.class")
, podczas gdy powinno być /modules/java.base/java/lang/AbstractMethodError.class
. To może być ustalona przez poprzedzenie brakującą /modules/
gdy ścieżka rodzic jest zgłaszane jako nieistniejące:
processRessource(Object.class.getResource("Object.class").toURI(), path -> {
Path p = path.getParent();
if(!Files.exists(p))
p = p.resolve("/modules").resolve(p.getRoot().relativize(p));
try(Stream<Path> stream = Files.list(p)) {
stream.forEach(System.out::println);
}
});
Potem będzie znowu działać ze wszystkimi wersjami i metod przechowywania.
Nie można utworzyć identyfikatora URI z zasobów znajdujących się w pliku jar. Można po prostu zapisać go do pliku tymczasowego, a następnie użyć go (java8):
Path path = File.createTempFile("some", "address").toPath();
Files.copy(ClassLoader.getSystemResourceAsStream("/path/to/resource"), path, StandardCopyOption.REPLACE_EXISTING);
- 1. Spring: Inject URL dla zasobu classpath
- 2. java.nio.file.Path dla adresów URL?
- 3. Jak serializować java.nio.file.Path z Gsonem?
- 4. Formularz dla zasobu zagnieżdżonego
- 5. plik klasy dla pliku java.nio.file.Path nie został znaleziony
- 6. ClassPath w Ant dla zadania Javac
- 7. Przełącz host zasobu dla kontrolera
- 8. Pobierz obiekt java.nio.file.Path z pliku java.io.File
- 9. Wildcard classpath @PropertySource
- 10. Jaka jest różnica między "classpath:" a "classpath: /" w Spring XML?
- 11. Czy klasa java --classpath zastępuje CLASSPATH lub dołącza do niej?
- 12. Java URL Protocols: classpath: /?
- 13. Classpath problem używając XPathFactory
- 14. Problemy z Jetty Classpath
- 15. Zrozumienie deklaracji classpath Eclipse
- 16. sbt Zadanie classpath
- 17. Opcja Java -classpath
- 18. Ant classpath Order
- 19. Jackson Databind classpath issue
- 20. Względne ścieżki w źródle classpath wiosny
- 21. Dodawanie katalogu do tomcat classpath
- 22. Dlaczego nie używasz argumentu classpath?
- 23. Problemy z log4.properties classpath
- 24. szyn: uzyskanie „nowej” drogi dla zagnieżdżonych zasobu
- 25. Dwie strony dla tego samego zasobu - ActiveAdmin
- 26. Nazwa zasobu Amazon (ARN) dla AWS SimpleDB
- 27. Szyny: Jak zmodyfikować testy dla zagnieżdżonego zasobu?
- 28. Classpath dla mrówek wtyczek podczas korzystania ANTBuilder z Gradle
- 29. Jak uzyskać dostęp do pliku/folderu w Javie 7 java.nio.file.Path?
- 30. Dodawanie folderu do Eclipse classpath
Cóż, biorąc długą drogę (gra słów nie przeznaczonych), masz 'Paths.get (URI)', następnie'URL.toURI() 'i ostatni' getResource() ', który zwraca' URL'. Możesz być w stanie połączyć je razem. Nie próbowałem jednak. – NilsH