Есть ли API для получения ресурса пути к классам (например, что я получил от Class.getResource(String)
) в качестве java.nio.file.Path
? В идеале я бы хотел использовать новые API-интерфейсы Path с ресурсами класса.java.nio.file.Path для ресурса classpath
ответ
Это один работает для меня:
return Paths.get(ClassLoader.getSystemResource(resourceName).toURI());
Это не будет работать с ресурсами в файлах .jar. – VGR
@VGR, если ресурсы в файле .jar могут попробовать это '\t \t \t Ресурс ресурса = новый ClassPathResource (" usage.txt "); \t \t \t BufferedReader reader = new BufferedReader (новый InputStreamReader (resource.getInputStream())); 'см. Http://stackoverflow.com/questions/25869428/classpath-resource-not-found-when-running-as- jar – zhuguowei
Оказывается, вы можете сделать это, используя встроенный Zip File System provider. Однако передача URI ресурса непосредственно на Paths.get
не будет работать; вместо этого, нужно сначала создать почтовый файловую систему для фляги URI без имени элемента, то обратитесь к записи в этой файловой системе:
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);
}
Будьте внимательны к вновь созданным ф. Второй вызов с использованием одного и того же баннера вызовет исключение, жалующееся на уже существующую файловую систему. Лучше попробовать try (FileSystem fs = ...) {return fs.getPath (entryName);} или если вы хотите, чтобы этот кешированный файл делал более совершенную обработку. В текущей форме это рискованно. – raisercostin
Помимо проблемы потенциально незамкнутой новой файловой системы, предположения о связи между схемами и необходимостью открытия новой файловой системы и недоумение с содержимым URI ограничивают полезность решения. Я установил [новый ответ] (http://stackoverflow.com/a/36021165/2711488), в котором показан общий подход, который упрощает работу и одновременно обрабатывает новые схемы, такие как новое хранилище классов Java 9. Он также работает, когда кто-то еще в приложении уже открыл файловую систему (или метод вызывается дважды для одного и того же баннера) ... – Holger
В зависимости от использования этого решения не закрытая 'newFileSystem' может привести к разворачиванию нескольких ресурсов навсегда. Хотя добавление @raisercostin позволяет избежать ошибки при попытке создать уже созданную файловую систему, если вы попытаетесь использовать возвращенный 'Path', вы получите' ClosedFileSystemException'. Ответ @Holger хорошо работает для меня. –
я написал небольшой вспомогательный метод для чтения Paths
из ваших ресурсов класса. Это очень удобно использовать, поскольку ему нужна только ссылка класса, который вы сохранили, а также имя самого ресурса.
public static Path getResourcePath(Class<?> resourceClass, String resourceName) throws URISyntaxException {
URL url = resourceClass.getResource(resourceName);
return Paths.get(url.toURI());
}
Гадать, что вы хотите сделать, это позвонить Files.lines (...) на ресурс, который исходит от пути к классам - возможно, внутри баночки.
Поскольку Oracle запутанного понятие, когда путь является путем, не делая getResource вернуть полезный путь, если он находится в файле JAR, что вам нужно сделать, это что-то вроде этого:
Stream<String> stream = new BufferedReader(new InputStreamReader(ClassLoader.getSystemResourceAsStream("/filename.txt"))).lines();
ли предыдущий «/» нужен в вашем случае, я не знаю, но в моем случае 'class.getResource' требует косой черты, но' getSystemResourceAsStream' не может найти файл, если префикс косой черты. – Adam
You необходимо определить файловую систему для чтения ресурсов из файла jar, как указано в https://docs.oracle.com/javase/8/docs/technotes/guides/io/fsp/zipfilesystemprovider.html. Я успешно прочитать ресурс из файла JAR с ниже коды:
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)) {
....
}
}
Наиболее общее решение выглядит следующим образом:
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);
}
}
}
Главное препятствие заключается в решении двух возможностей, либо, имея существующий файловую систему, которую мы должны использовать, но не закрывать (например, с file
URI или будущим хранилищем модулей Java 9) или открывать и тем самым безопасно закрывать файловую систему самостоятельно (например, файлы zip/jar).
Следовательно, решение выше инкапсулирует фактическое действие в interface
, обрабатывает оба случая, безопасно закрывается впоследствии во втором случае и работает с Java 7 на Java 9. Оно проверяет, есть ли открытая файловая система, прежде чем открывать новый, поэтому он также работает в том случае, если другой компонент вашего приложения уже открыл файловую систему для того же файла zip/jar.
Он может использоваться во всех версиях Java, указанных выше, например. в список содержимого пакета (java.lang
в примере) как Path
с, как это:
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);
}
}
});
С Java 8 или новее, вы можете использовать лямбда-выражения или ссылки на метод, чтобы представлять фактические действия, например,
processRessource(Object.class.getResource("Object.class").toURI(), path -> {
try(Stream<Path> stream = Files.list(path.getParent())) {
stream.forEach(System.out::println);
}
});
сделать то же самое.
Окончательный выпуск модульной системы Java 9 нарушил приведенный выше пример кода.JRE непоследовательно возвращает путь /java.base/java/lang/Object.class
для Object.class.getResource("Object.class")
, тогда как он должен быть /modules/java.base/java/lang/AbstractMethodError.class
. Это может быть исправлено, предваряя недостающую /modules/
, когда родительский путь сообщается несуществующими:
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);
}
});
Затем он снова будет работать со всеми версиями и методов хранения.
Вы не можете создать URI из ресурсов внутри файла jar. Вы можете просто записать его на временный файл, а затем использовать его (java8):
Path path = File.createTempFile("some", "address").toPath();
Files.copy(ClassLoader.getSystemResourceAsStream("/path/to/resource"), path, StandardCopyOption.REPLACE_EXISTING);
Ну, взяв длинный путь (каламбур), то есть 'Paths.get (URI)', то'URL.toURI() 'и last' getResource() ', который возвращает' URL'. Возможно, вы сможете объединить их. Не пробовал, хотя. – NilsH