открытый ресурс с относительным путем в 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/… .
Жером Верстриндж
См. Также stackoverflow.com/questions/204784/…
Вадим

Ответы:

48

Укажите путь относительно загрузчика классов, а не класса, из которого вы получаете загрузчик. Например:

resourcesloader.class.getClassLoader().getResource("package1/resources/repository/SSL-Key/cert.jks").toString();
jonathan.cone
источник
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
@Ava Добавьте тестовую папку в качестве исходной папки, и все готово!
Аакаш Парашар,
@Ava, я уверен, что это поздно для тебя, но может кому-то помочь. Вам нужно выполнить mvn clean test-compileкоманду, как это происходит compileв жизненном цикле Maven . Это сгенерирует target/test-classes.
Александр Радченко
35

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

Проект /
  src / // исходный код приложения
    org /
      мой проект/
        MyClass.java
  test / // модульные тесты
  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) .

E-богатый
источник
1
. + 1 за предложение ClassLoader
pyb
1
Лучший ответ на эту тему! Совет о том, чтобы не использовать /в начале пути ресурса, был ключевым!
Кайхадрин
10

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

Если вы используете абсолютный путь, оба метода getResource будут запускаться в корневой папке.

Nbeyer
источник
Не забывайте о последствиях/
Жилберто
@nbeyer Почему использование getResourceс абсолютным путем начинается с корневой папки? Разве цель абсолютного пути не абсолютна ?
atjua 07
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 хотел найти ресурс в пути к классам (скорее всего, в банке, созданной во время сборки). Этот метод не обеспечивает способа достижения этой цели - вы не можете указать 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папку и из списка исходных папок проекта и вернув ее (проект> свойства> путь сборки java> источник> удалить / добавить папку), я смог решить эту проблему.

Пол Мира
источник
2
resourcesloader.class.getClass()

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

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

Это означает, что вы пытаетесь загрузить ресурс с помощью класса начальной загрузки.

Вместо этого вы, вероятно, захотите что-то вроде:

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

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

Том Хотин - tackline
источник
1

Выполняются ли следующие работы?

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

По какой причине вы не можете указать полный путь, включая пакет?

RichH
источник
1

Следуя двум ответам, упомянутым выше. Первый

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

Должно быть одно и то же?

manocha_ak
источник
1

Чтобы получить реальный путь к файлу, вы можете попробовать следующее:

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

Resourceloader - это имя класса здесь. "resources / repository / SSL-Key / cert.jks" - относительный путь к файлу. Если бы у вас был guiclass в ./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();
Альферд Нобель
источник
0

Использовать этот:

resourcesloader.class.getClassLoader().getResource("/path/to/file").**getPath();**
Олег Полторацкий
источник