TL; DR
В среде Spring Framework основное внимание уделяется использованию служебных программ Spring для обработки ресурсов (например, ResourceUtils
class ), которые красиво инкапсулируют низкоуровневые операции ввода-вывода, зависящие от операционной системы. ResourceUtils
уже содержит несколько ловушек, чтобы выяснить, является ли запущенный вами проект в разобранном виде (запущен в IDE) или упакован (внутри файла JAR).
Ответ, предоставленный Каролом, кажется самым простым и относительно пуленепробиваемым, пока вам не понадобится определенный уровень гибкости для указания местоположения файла (внутри файла JAR, но с возможностью определять его внешне и предоставлять где-то в файловой системе). ). Тогда подход с методом getResourceAsStream()
не будет работать.
Стандартный Java IO (java.nio
) использует FileSystemProvider
классы для делегирования операций ввода-вывода (таких как создание, чтение и удаление файлов).
Поставщик определяется по схеме URI . Поставщик по умолчанию идентифицируется схемой URI «файл». Он создает файловую систему, которая обеспечивает доступ к файловым системам, доступным для виртуальной машины Java. Класс FileSystems определяет, как расположены и загружаются поставщики файловой системы.
Итак, если ваш файл находится где-то в файловой системе, проблем нет, и все работает нормально. Технически, URL, возвращаемый Application.class.getResource("").toURI()
, начинается с file: // и содержит допустимый путь к файловой системе.
Сказав, что, когда ваш файл "приземляется" внутри файла jar, Application.class.getResource("").toURI()
возвращает что-то более похожее на file: // {jar-location}! / (обратите внимание на восклицательный знак), который не является допустимым путем к схеме файла, и Java не знает, как его обработать. Дополнительный поставщик файловой системы нуждается в регистрации.
FileSystems.newFileSystem(uri, emptyMap());
Java вычисляет (на основе URI) схему и регистрирует новую файловую систему. Отныне могут использоваться стандартные файловые операции java.nio
.
Например, если у вас есть файлы в папке / webapp , которые могут (но не обязательно) находиться внутри файла jar, и вы хотите перечислить их.
// Load zip specific filesystem provider when run from inside a fat-jar
URI uri = Application.class.getResource("").toURI();
if (uri.toString().contains("!")) {
FileSystems.newFileSystem(uri, emptyMap());
}
URI rootFolder = Application.class.getResource("/webapp").toURI();
List<Path> banners = Files.list(Paths.get(rootFolder))
.collect(Collectors.toList());
Random rand = new Random();
Path path = banners.get(rand.nextInt(banners.size()));
log.info("Random image: {}", path.getFileName());
byte[] bytes = Files.readAllBytes(path);
Установка нового поставщика файловой системы является глобальной и должна выполняться только один раз.