відкритий ресурс із відносним шляхом у Java


84

У моїй програмі Java мені потрібно отримати деякі файли та каталоги.

Це структура програми:

./main.java
./package1/guiclass.java
./package1/resources/resourcesloader.java
./package1/resources/repository/modules/   -> this is the dir I need to get
./package1/resources/repository/SSL-Key/cert.jks    -> this is the file I need to get

guiclass завантажує клас завантажувача ресурсів, який завантажує мої ресурси (каталог і файл).

Що стосується файлу, я намагався

resourcesloader.class.getClass().getResource("repository/SSL-Key/cert.jks").toString()

для того, щоб отримати справжній шлях, але цей шлях не працює.

Я не уявляю, який шлях використовувати для каталогу.


1
class.getClass () - не те саме, що class.getClassLoader (). Існує також інше рішення, getResourceAsStream (), використовуючи клас у тому ж пакеті, що і ваш ресурс. Детальніше: tshikatshikaaa.blogspot.nl/2012/07/… .
Jérôme Verstrynge

Відповіді:


48

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

resourcesloader.class.getClassLoader().getResource("package1/resources/repository/SSL-Key/cert.jks").toString();

161

У мене були проблеми з використанням getClass().getResource("filename.txt")методу. Після прочитання інструкцій з Java-документів, якщо ваш ресурс не в тому ж пакеті, що і клас, з якого ви намагаєтесь отримати доступ до ресурсу, вам потрібно вказати йому відносний шлях, починаючи з '/'. Рекомендованою стратегією є розміщення файлів ресурсів у папці "ресурси" в кореневому каталозі. Так, наприклад, якщо у вас є структура:

src/main/com/mycompany/myapp

тоді ви можете додати папку ресурсів, як рекомендує maven у:

src/main/resources

крім того, ви можете додати підпапки в папку ресурсів

src/main/resources/textfiles

і скажіть, що ваш файл називається, myfile.txtтак ви маєте

src/main/resources/textfiles/myfile.txt

Зараз тут виникає дурна проблема із шляхами. Скажімо, у вас є клас com.mycompany.myapp packageі ви хочете отримати доступ до myfile.txtфайлу з вашої папки ресурсів. Деякі кажуть, що вам потрібно дати:

"/main/resources/textfiles/myfile.txt" path

або

"/resources/textfiles/myfile.txt"

обидва вони помилкові. Після запуску mvn clean compileфайли та папки копіюються в:

myapp/target/classes 

папку. Але папки ресурсів немає, лише папки в папці ресурси. Отже, у вас є:

myapp/target/classes/textfiles/myfile.txt

myapp/target/classes/com/mycompany/myapp/*

тож правильний шлях до getClass().getResource("")методу:

"/textfiles/myfile.txt"

ось:

getClass().getResource("/textfiles/myfile.txt")

Це більше не поверне значення null, але поверне ваш клас. Сподіваюся, це комусь допоможе. Мені дивно, що "resources"папка також не копіюється, а лише підпапки та файли безпосередньо в "resources"папці. Мені здається логічним, що "resources"папку також можна знайти під"myapp/target/classes"


1
У моєму target/classesфайлі я бачу лише файли під основними ресурсами, а не тестові ресурси. Чому?
Ава

@Ava Додайте тестову папку як вихідну папку, і все готово!
Aakash Parashar

@Ava, впевнений, це пізня відповідь для вас, але ви можете комусь допомогти. Вам потрібно виконати mvn clean test-compileкоманду, як це відбувається compileв життєвому циклі Maven . Це породить target/test-classes.
Олександр Радченко

34

В надії надати додаткову інформацію для тих, хто не підбирає це так швидко, як інші, я хотів би надати свій сценарій, оскільки він має дещо інше налаштування. Мій проект було налаштовано з наступною структурою каталогів (за допомогою Eclipse):

Проект /
  src / // вихідний код програми
    орг /
      мійпроект /
        MyClass.java
  тест / // одиничні тести
  res / // ресурси
    images / // PNG зображення для піктограм
      my-image.png
    xml / // XSD-файли для перевірки XML-файлів за допомогою JAXB
      my-schema.xsd
    conf / // файл .conf за замовчуванням для Log4j
      log4j.conf
  lib / // бібліотеки, додані до шляху побудови через налаштування проекту

У мене були проблеми із завантаженням ресурсів із каталогу res . Я хотів, щоб усі мої ресурси були окремими від вихідного коду (просто для цілей управління / організації). Отже, мені потрібно було додати каталог res до шляху побудови, а потім отримати доступ до ресурсу за допомогою:

static final ClassLoader loader = MyClass.class.getClassLoader();

// in some function
loader.getResource("images/my-image.png");
loader.getResource("xml/my-schema.xsd");
loader.getResource("conf/log4j.conf");

ПРИМІТКА. Значення /пропущено з початку рядка ресурсу, оскільки я використовую ClassLoader.getResource (String) замість Class.getResource (String) .


1
. + 1 за пропозицію ClassLoader
pyb

1
Найкраща відповідь на цю тему! Порада щодо невикористання /на початку шляху до ресурсу була ключовою!
Кайхадрін,

10

Коли ви використовуєте 'getResource' у класі, відносний шлях вирішується на основі пакету, в якому знаходиться клас. Коли ви використовуєте 'getResource' у ClassLoader, відносний шлях вирішується на основі кореневої папки.

Якщо ви використовуєте абсолютний шлях, обидва методи 'getResource' почнуться в кореневій папці.


Не забувайте про наслідки/
Gilberto

@nbeyer Чому використання getResourceз абсолютним шляхом починається з кореневої папки? Хіба мета абсолютного шляху не є абсолютною ?
atjua

10

@GianCarlo: Ви можете спробувати викликати системну властивість user.dir, яка надасть вам корінь вашого проекту java, а потім додасть цей шлях до вашого відносного шляху, наприклад:

String root = System.getProperty("user.dir");
String filepath = "/path/to/yourfile.txt"; // in case of Windows: "\\path \\to\\yourfile.txt
String abspath = root+filepath;



// using above path read your file into byte []
File file = new File(abspath);
FileInputStream fis = new FileInputStream(file);
byte []filebytes = new byte[(int)file.length()];
fis.read(filebytes);

1
OP хотів знайти ресурс у шляху до класу (швидше за все, у банку, створеній під час го побудови). Цей метод не забезпечує способу досягнення цієї мети - ви не можете вказати a Fileна ресурс у файлі jar, а лише на правильний запис у файловій системі (наприклад, сам jar).
Аттіла

Мені подобається ідея отримати "user.dir", щоб побачити бажаний шлях. Дякую
YouAreAwesome

5

Для тих, хто використовує eclipse + maven. Скажімо, ви намагаєтесь отримати доступ до файлу images/pic.jpgв src/main/resources. Робимо це так:

ClassLoader loader = MyClass.class.getClassLoader();
File file = new File(loader.getResource("images/pic.jpg").getFile());

є абсолютно правильним, але може призвести до винятку нульового покажчика. Схоже, eclipse не розпізнає папки у структурі каталогів maven відразу як вихідні папки. Видаливши та src/main/resourcesпапку зі списку вихідних папок проекту та повернувши її назад (project> properties> java build path> source> remove / add Folder), я зміг це вирішити.


2
resourcesloader.class.getClass()

Можна розбити на:

Class<resourcesloader> clazz = resourceloader.class;
Class<Class> classClass = clazz.getClass();

А це означає, що ви намагаєтесь завантажити ресурс за допомогою класу bootstrap.

Натомість вам, напевно, потрібно щось на зразок:

resourcesloader.class.getResource("repository/SSL-Key/cert.jks").toString()

Якби тільки javac попереджав про виклик статичних методів у нестатичному контексті ...


1

Ви виконуєте наступну роботу?

resourcesloader.class.getClass().getResource("/package1/resources/repository/SSL-Key/cert.jks")

Чи є причина, по якій ви не можете вказати повний шлях, включаючи пакет?


1

Поєднуючись із двома відповідями, згаданими вище. Перший

resourcesloader.class.getClassLoader().getResource("package1/resources/repository/SSL-Key/cert.jks").toString();
resourcesloader.class.getResource("repository/SSL-Key/cert.jks").toString()

Має бути одне і те ж?


1

Для того, щоб отримати реальний шлях до файлу, ви можете спробувати наступне:

URL fileUrl = Resourceloader.class.getResource("resources/repository/SSL-Key/cert.jks");
String pathToClass = fileUrl.getPath;    

Завантажувач ресурсів - це назва класу. "resources / repository / SSL-Key / cert.jks" - це відносний шлях до файлу. Якби у вас був ваш стиль в ./package1/java з рештою структури папки, що залишилася, ви б взяли "../resources/repository/SSL-Key/cert.jks" як відносний шлях через правила, що визначають відносний шлях.

Таким чином ви можете прочитати свій файл за допомогою BufferedReader. НЕ ВИКОРИСТОВУЙТЕ РЯДКУ, щоб визначити шлях до файлу, тому що якщо на вашому шляху є пробіли або деякі символи з не англійського алфавіту, ви отримаєте проблеми, і файл не буде знайдений.

BufferedReader bufferedReader = new BufferedReader(
                        new InputStreamReader(fileUrl.openStream()));

0

Я зробив невелику модифікацію одного вкладиша @ jonathan.cone (додавши .getFile()), щоб уникнути винятку нульових покажчиків та встановити шлях до каталогу даних. Ось, що мені вдалося:

String realmID = new java.util.Scanner(new java.io.File(RandomDataGenerator.class.getClassLoader().getResource("data/aa-qa-id.csv").getFile().toString())).next();

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.