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


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.