Як я можу отримати ресурс "Папка" з моєї баночки Файл?


139

У мене в папці ресурсів папка / пакет в корені мого проекту, я "не хочу" завантажити певний файл. Якби я хотів завантажити певний файл, я б використав class.getResourceAsStream, і я був би в порядку !! Що я насправді хочу зробити, це завантажити "папку" у папку "Ресурси", петлю на Файли всередині цієї папки та отримати потік до кожного файлу та прочитати у вмісті ... Припустимо, що імена файлів не визначаються до часу виконання ... Що я повинен зробити? Чи є спосіб отримати список файлів всередині папки у вашій банку Файл? Зауважте, що файл Jar з ресурсами - це той самий файл jar, з якого запускається код ...

Спасибі заздалегідь...




5
Перший - про вилучення файлу jar, який є останньою справою, яку я хочу спробувати, як, наприклад, якщо гірше - прийде до гіршого !! Якщо я хочу витягнути файли, я б просто помістив їх у свою інсталяційну папку під час встановлення! Я хочу отримати доступ до них зсередини банки, і моя причина полягає в тому, що якщо getResourceAsStream може отримати доступ до файлу, Java також має змогу досліджувати папки в цій банку, не потребуючи її витягувати !! Але дякую ...
Мостафа Зейналі

Відповіді:


111

Нарешті, я знайшов рішення:

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). Ви можете його видалити, якщо вам це не подобається.


Оновлена ​​правильна відповідь. Хоча це не те, що я хотів би зробити, особливо в коді з 34000+ вихідними файлами ... Але це, здається, єдине рішення. Дякую.
Мостафа Зейналі

4
FYI, це не працює при запуску з веб-запуску, оскільки getPath повертає щось відносно домену сервера.
амос

1
Не думайте, що це буде спрацьовувати, якщо шлях знаходиться в банку, призведе до цієї помилки при перетворенні TOURI: java.lang.IllegalArgumentException: URI не є ієрархічним
tribbloid

4
Працює лише для файлу з однією jar-файлом, не працює для вилучення ресурсів із залежностей в іншій jar
tribbloid

2
Це не безпечне рішення, оскільки: 1. Він передбачає, що файл .jar - це локальний файл у тій же системі; 2. URL.getPath () не повертає дійсного імені файлу, він просто повертає частину шляху URL-адреси з усіма відсотками-втечами недоторканими; 3. ProtectionDomain.getCodeSource () може повернути нуль .
VGR

14

Спробуйте наступне.
Зробіть шлях до ресурсу "<PathRelativeToThisClassFile>/<ResourceDirectory>" Напр., Якщо шлях вашого класу com.abc.package.MyClass і ваші файли resoure знаходяться в межах 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/");

27
Дякую за витрачений час та зусилля, але це НЕ працює, коли ваш код знаходиться у файлі .jar, а ваші ресурси також у цьому файлі .jar. Якщо ви знаходитесь у .jar-файлі, ви не можете створити файл (), а також не можете отримати URL-адресу для цієї папки ... я особисто з цим умирився і просто перерахував кожен файл у XML ... я не не думаю, що ти взагалі можеш це зробити для папки всередині файлу jar ...
Mostafa Zeinali

2
Вибачте, що у вас виникли проблеми. Однак це насправді працює, коли база вашого коду знаходиться у файлі jar, а ваші ресурси також є у цьому файлі jar. Ви не створюєте File () на диску - ви читаєте файл у файлі jar в пам'ять Java. Зауважте, що ClassLoader із задоволенням обробляє файл jar, еквівалентний директорії на диску. Ось деталі з джерела:
Glen Best

1
Просто запустив код на банку і отримав помилку ... ой. V вибачте, мій поганий. Потрібно обробити шлях URL-адреси jar з "Файл: ...! / Dir1 / dir2 ...". Два виправлення: stackoverflow.com/questions/1429172 / ... . АБО Рядок jarPath = dirURL.getPath () подстрок ( "!" 5, dirURL.getPath () IndexOf ()); JarFile jar = новий JarFile (URLDecoder.decode (jarPath, "UTF-8")); Перерахування <JarEntry> записів = jar.entries (); while (entries.hasMoreElements ()) {// робити щось}
Glen Best

3
З боку Javadoc очевидно, що метод ЗАВЖДИ не гарантовано повернути файл за будь-яких обставин. Але, якщо ви насправді читаєте Q, OP гарантується на 100% для роботи з файлами та папками за конструкцією. Q просить отримати доступ до каталогів та файлів - це більш конкретно, ніж узагальнена абстракція API. Перетворення у файл є відповідним та правильним для задоволення потреби. Будь ласка, прочитайте належним чином питання, перш ніж публікувати такі суперечливі коментарі. Ура.
Глен Кращий

7
ОП не працює з файлами та каталогами. Він працює з ресурсами у файлі JAR. Ресурси у файлі JAR не є файлами та каталогами і не можуть бути перераховані з Fileкласом. Цей код не працює з ресурсами всередині файлу JAR. Період.
Маркіз Лорн

7

Я знаю, це багато років тому. Але просто для інших людей трапляється ця тема. Що ви можете зробити, це використовувати getResourceAsStream()метод з контуром до каталогу, а вхідний потік буде мати всі файли з цього режиму. Після цього ви можете сформулювати шлях dir з кожним іменем файлу та викликати getResourceAsStream для кожного файлу в циклі.


7
Це добре працює, якщо ви не плануєте розбирати речі, як виявилося.
Tustin2121

1
Я думаю, що це має бути прийнятим рішенням, оскільки воно є чистим і не потребує обробки версій jar та IDE в окремих випадках. Хоча я не впевнений, чому getResource не знаходить папки, але getResourceAsStream робить.
Рагурам Онті Шрінівасан

6

У мене була така ж проблема, коли я намагався завантажити деякі конфігурації hadoop з ресурсів, запакованих у банку ... і на 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());
    }
}

Це добре працювало для мене. Тільки я переключив "Path jarFile = Paths.get (jar.toString (). Substring (" файл: ". Length ()));" з 'Path jarFile = Paths.get (jar.toURI ());' щоб він працював у Windows. Також використано спробу з оператором ресурсу для об'єкта FileSystem.
Jarle Jacobsen

Це працювало для мене! Я запускав програму dropwizard у докер.
nIKUNJ

4

Наступний код повертає шукану "папку" як Path незалежно від того, знаходиться вона в банку чи ні.

  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+.


Приємно! Я маю додати, що FileSystem є закритим, що означає, що вам доведеться закрити його в якийсь момент, щоб звільнити системні ресурси. Звичайно, повернений шлях стане недійсним відразу після цього.
Кирило Гамазков

Зауважте, що у випадку файлу jar назву ресурсу (тут пакет + folder), як видається, ігнорують під час створення файлової системи. Тому getPathне повертається folder/path/to/..., а лише path/to/....
Marcono1234

1

Інше рішення, ви можете зробити це, використовуючи 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())
}

0

Просте ... використання OSGi. В OSGi ви можете переглядати записи своїх пакетів з FindEntries і findPaths.


10
Якщо він включає OSGI, я навряд чи називаю це "простим". Але якщо ви вже користуєтесь OSGI ... так, звичайно. Але пропонувати перейти на OSGI просто для вирішення цієї конкретної проблеми здається трохи занадто.
Кріс

OSGi також вирішує багато інших проблем, і сьогодні це дуже просто почати. Дивіться навчальні матеріали OSGi enRoute
Пітер

Я б тримався подалі від OSGi, якщо вам вже не потрібно використовувати його. Над розробленою програмою Bloatware, яка вирішує проблеми розгортання ІМО 90-х.
user2337270

-1

Всередині мого файлу банку в мене була папка під назвою "Завантажити", у цій папці були ще три текстові файли, і мені потрібно було мати абсолютно таку ж папку та файли поза файлом 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);

1
Привіт, дякую за відповідь, але, бачте, вам потрібно було знати ім’я кожного файлу у цій папці під час написання коду; і потрібно було чітко назвати кожного. Що я шукав, це метод ітерації файлів всередині папки та отримання їх імен під час виконання, щоб я міг додавати ресурси в папку, не змінюючи код, знаючи, що код також буде обробляти їх. Дякую за ваш час. : 3
Мостафа Зейналі

-1

Як зазначають інші відповіді, як тільки ресурси знаходяться всередині файлу jar, речі стають справді некрасивими. У нашому випадку це рішення:

https://stackoverflow.com/a/13227570/516188

дуже добре працює в тестах (оскільки при запуску тестів код не упаковується у файл jar), але не працює, коли програма насправді працює нормально. Тож, що я зробив, це ... Я жорстко кодую список файлів у додатку, але у мене є тест, який читає фактичний список з диска (може це зробити, оскільки це працює в тестах) і не працює, якщо фактичний список не відповідає не відповідає списку, який програма повертає.

Таким чином, у моєму додатку є простий код (без хитрощів), і я впевнений, що не забув додати нову запис у список завдяки тесту.


-25

Це посилання розповідає, як.

Магія - метод getResourceAsStream ():

InputStream is = 
this.getClass().getClassLoader().getResourceAsStream("yourpackage/mypackage/myfile.xml")

20
Не чувак !! Я НЕ хочу жодного файлу !! Я хочу цілу папку, суб-файли якої не визначені перед запусками !!!
Мостафа Зейналі
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.