Как я могу получить ресурс "Папка" из моего файла JAR?
У меня есть папка / пакет ресурсов в корне моего проекта, я не хочу загружать определенный файл. Если бы я хотел загрузить определенный файл, я бы использовал class.getResourceAsStream, и я был бы в порядке!! Что я на самом деле хочу сделать, так это загрузить "Папку" в папке ресурсов, зациклить файлы внутри этой папки, получить поток для каждого файла и прочитать содержимое... Предположим, что имена файлов не определены до времени выполнения... Что я должен делать? Есть ли способ получить список файлов внутри папки в вашем файле jar? Обратите внимание, что файл Jar с ресурсами является тем же файлом JAR, из которого выполняется код...
Заранее спасибо...
13 ответов
Наконец, я нашел решение:
final String path = "sample/folder";
final File jarFile = new File(getClass().getProtectionDomain().getCodeSource().getLocation().getPath());
if(jarFile.isFile()) { // Run with JAR file
final JarFile jar = new JarFile(jarFile);
final Enumeration<JarEntry> entries = jar.entries(); //gives ALL entries in jar
while(entries.hasMoreElements()) {
final String name = entries.nextElement().getName();
if (name.startsWith(path + "/")) { //filter according to the path
System.out.println(name);
}
}
jar.close();
} else { // Run with IDE
final URL url = Launcher.class.getResource("/" + path);
if (url != null) {
try {
final File apps = new File(url.toURI());
for (File app : apps.listFiles()) {
System.out.println(app);
}
} catch (URISyntaxException ex) {
// never happens
}
}
}
Второй блок просто работает, когда вы запускаете приложение в IDE (не с файлом JAR). Вы можете удалить его, если вам это не нравится.
Попробуйте следующее.
Сделать путь к ресурсу "<PathRelativeToThisClassFile>/<ResourceDirectory>"
Например, если ваш путь к классу - com.abc.package.MyClass, а ваши файлы ресурсов находятся в src/com/abc/package/resources/:
URL url = MyClass.class.getResource("resources/");
if (url == null) {
// error - missing folder
} else {
File dir = new File(url.toURI());
for (File nextFile : dir.listFiles()) {
// Do something with nextFile
}
}
Вы также можете использовать
URL url = MyClass.class.getResource("/com/abc/package/resources/");
Следующий код возвращает искомую "папку" как путь независимо от того, находится она внутри фляги или нет.
private Path getFolderPath() throws URISyntaxException, IOException {
URI uri = getClass().getClassLoader().getResource("folder").toURI();
if ("jar".equals(uri.getScheme())) {
FileSystem fileSystem = FileSystems.newFileSystem(uri, Collections.emptyMap(), null);
return fileSystem.getPath("path/to/folder/inside/jar");
} else {
return Paths.get(uri);
}
}
Требуется Java 7+.
Я знаю, что это много лет назад. Но только для других людей попадается эта тема. Что вы могли бы сделать, это использовать getResourceAsStream()
метод с путем к каталогу, и входной поток будет иметь все имена файлов из этого каталога. После этого вы можете объединить путь dir с каждым именем файла и вызвать getResourceAsStream для каждого файла в цикле.
У меня была такая же проблема, когда я пытался загрузить некоторые конфигурации hadoop из ресурсов, упакованных в jar... как в IDE, так и в jar (версия для выпуска).
я нашел java.nio.file.DirectoryStream
работать лучше всего, чтобы перебрать содержимое каталога как в локальной файловой системе, так и в jar.
String fooFolder = "/foo/folder";
....
ClassLoader classLoader = foofClass.class.getClassLoader();
try {
uri = classLoader.getResource(fooFolder).toURI();
} catch (URISyntaxException e) {
throw new FooException(e.getMessage());
} catch (NullPointerException e){
throw new FooException(e.getMessage());
}
if(uri == null){
throw new FooException("something is wrong directory or files missing");
}
/** i want to know if i am inside the jar or working on the IDE*/
if(uri.getScheme().contains("jar")){
/** jar case */
try{
URL jar = FooClass.class.getProtectionDomain().getCodeSource().getLocation();
//jar.toString() begins with file:
//i want to trim it out...
Path jarFile = Paths.get(jar.toString().substring("file:".length()));
FileSystem fs = FileSystems.newFileSystem(jarFile, null);
DirectoryStream<Path> directoryStream = Files.newDirectoryStream(fs.getPath(fooFolder));
for(Path p: directoryStream){
InputStream is = FooClass.class.getResourceAsStream(p.toString()) ;
performFooOverInputStream(is);
/** your logic here **/
}
}catch(IOException e) {
throw new FooException(e.getMessage());
}
}
else{
/** IDE case */
Path path = Paths.get(uri);
try {
DirectoryStream<Path> directoryStream = Files.newDirectoryStream(path);
for(Path p : directoryStream){
InputStream is = new FileInputStream(p.toFile());
performFooOverInputStream(is);
}
} catch (IOException _e) {
throw new FooException(_e.getMessage());
}
}
Если вы используете Spring, вы можете использовать
org.springframework.core.io.support.PathMatchingResourcePatternResolver
и разобраться с
Resource
объекты, а не файлы. Это работает при запуске внутри и вне файла Jar.
PathMatchingResourcePatternResolver r = new PathMatchingResourcePatternResolver();
Resource[] resources = r.getResources("/myfolder/*");
Затем вы можете получить доступ к данным, используя
getInputStream
и имя файла из
getFilename
.
Обратите внимание, что он все равно не удастся, если вы попытаетесь использовать
getFile
во время бега из кувшина.
Другое решение, вы можете сделать это с помощью ResourceLoader
как это:
import org.springframework.core.io.Resource;
import org.apache.commons.io.FileUtils;
@Autowire
private ResourceLoader resourceLoader;
...
Resource resource = resourceLoader.getResource("classpath:/path/to/you/dir");
File file = resource.getFile();
Iterator<File> fi = FileUtils.iterateFiles(file, null, true);
while(fi.hasNext()) {
load(fi.next())
}
Код ниже получает файлы .yaml из настраиваемого каталога ресурсов.
ClassLoader classLoader = this.getClass().getClassLoader();
URI uri = classLoader.getResource(directoryPath).toURI();
if("jar".equalsIgnoreCase(uri.getScheme())){
Pattern pattern = Pattern.compile("^.+" +"/classes/" + directoryPath + "/.+.yaml$");
log.debug("pattern {} ", pattern.pattern());
ApplicationHome home = new ApplicationHome(SomeApplication.class);
JarFile file = new JarFile(home.getSource());
Enumeration<JarEntry> jarEntries = file.entries() ;
while(jarEntries.hasMoreElements()){
JarEntry entry = jarEntries.nextElement();
Matcher matcher = pattern.matcher(entry.getName());
if(matcher.find()){
InputStream in =
file.getInputStream(entry);
//work on the stream
}
}
}else{
//When Spring boot application executed through Non-Jar strategy like through IDE or as a War.
String path = uri.getPath();
File[] files = new File(path).listFiles();
for(File file: files){
if(file != null){
try {
InputStream is = new FileInputStream(file);
//work on stream
} catch (Exception e) {
log.error("Exception while parsing file yaml file {} : {} " , file.getAbsolutePath(), e.getMessage());
}
}else{
log.warn("File Object is null while parsing yaml file");
}
}
}
Мне потребовалось 2-3 дня, чтобы заставить это работать, чтобы иметь один и тот же URL-адрес, который работает как для Jar, так и для локального, URL-адрес (или путь) должен быть относительным путем от корня репозитория.
..имеется в виду расположение вашего файла или папки из вашего
src
папка.
could be "/main/resources/your-folder/" or "/client/notes/somefile.md"
Что бы это ни было, чтобы ваш JAR-файл мог его найти, URL-адрес должен быть относительным путем от корня репозитория.
it must be "src/main/resources/your-folder/" or "src/client/notes/somefile.md"
Теперь вы получили упражнение, и, к счастью для пользователей Intellij Idea, вы можете получить правильный путь с помощьюa right-click on the folder or file -> copy Path/Reference.. -> Path From Repository Root (this is it)
Наконец, вставьте его и делайте свое дело.
Просто... используйте OSGi. В OSGi вы можете перебирать записи вашего Bundle с помощью findEntries и findPaths.
Как указывают другие ответы, как только ресурсы находятся внутри jar-файла, все становится действительно безобразным. В нашем случае это решение:
/questions/19037510/kak-ya-mogu-poluchit-resurs-papka-iz-moego-fajla-jar/19037547#19037547
очень хорошо работает в тестах (поскольку при запуске тестов код не упаковывается в файл jar), но не работает, когда приложение действительно работает нормально. Итак, что я сделал... Я жестко закодировал список файлов в приложении, но у меня есть тест, который считывает фактический список с диска (может сделать это, так как это работает в тестах) и завершается неудачей, если реальный список не не соответствует списку, который возвращает приложение.
Таким образом, у меня есть простой код в моем приложении (без хитростей), и я уверен, что я не забыл добавить новую запись в список благодаря тесту.
Внутри моего jar-файла у меня была папка с названием Upload, в этой папке было три других текстовых файла, и мне нужно было иметь точно такую же папку и файлы за пределами jar-файла, я использовал код ниже:
URL inputUrl = getClass().getResource("/upload/blabla1.txt");
File dest1 = new File("upload/blabla1.txt");
FileUtils.copyURLToFile(inputUrl, dest1);
URL inputUrl2 = getClass().getResource("/upload/blabla2.txt");
File dest2 = new File("upload/blabla2.txt");
FileUtils.copyURLToFile(inputUrl2, dest2);
URL inputUrl3 = getClass().getResource("/upload/blabla3.txt");
File dest3 = new File("upload/Bblabla3.txt");
FileUtils.copyURLToFile(inputUrl3, dest3);
Эта ссылка говорит вам, как.
Волшебство - это метод getResourceAsStream():
InputStream is =
this.getClass().getClassLoader().getResourceAsStream("yourpackage/mypackage/myfile.xml")