?

Log in

Previous Entry | Next Entry

В последнее время неоднократно всплывает тема загрузки ресурсов. Вкратце: «Я загружаю картинку из c:\work\image.gif, а когда запускаю программу из jar-файла/на другом компьютере – она не грузится. Что делать?».

Между тем, ничего сложного тут нет. Надо только понимать принципы.

Прежде всего, грузить ресурсы по абсолютному адресу на диске – занятие бесперспективное. Думаю, сами прекрасно понимаете, почему – убрали файл с диска, и «прощай ресурс». Всё свое надо носить с собой.

Второй вариант, который я часто вижу, – загрузка ресурса из jar-файла. Но тут очень часто делается одна ошибка – ресурс пытаются грузить через класс java.io.File. При том, что этот класс предназначен только для работы с файловыми системами.

Хотя сама идея правильная. Нужный ресурс действительно необходимо поместить в jar-файл. Надо только понимать, как его оттуда загрузить. Вот об этом я и расскажу.

Для загрузки ресурса служат методы java.lang.Class.getResource(String), java.lang.Class.getResourceAsStream(String), java.lang.ClassLoader.getResource(String) и java.lang.ClassLoader.getResourceAsStream(String). Методы Class-а делегируют вызовы ClassLoader-у.

getResource(String) по имени ресурса возвращает java.net.URL, через который можно получить этот ресурс. getResourceAsStream(String), как нетрудно догадаться, возвращает java.io.InputStream, через который ресурс можно прочитать.

Имя ресурса представляет собой путь к ресурсу. Есть одна существенная тонкость, а именно – как оно интерпретируется.

Имя может быть абсолютным и относительным. Внешнее отличие – абсолютное имя начинается с символа '/'. В первом случае ресурс ищется относительно корня classpath. Т.е. берутся все пути и jar-файлы, входящие в classpath, и ресурс ищется относительно совокупности этих точек. Если же имя относительное – к нему в начало приписывается путь, полученный из пакета текущего класса. Далее поиск ведется как в случае абсолютного имени.

Проще это понять на примерах. Пусть у нас задан classpath: c:\work\myproject\classes;c:\lib\lib.jar. Код примера находится в классе ru.skipy.test.ResourceLoadingTest.

Пример 1. Мы используем конструкцию getClass().getResource("/images/logo.png"). Поскольку имя начинается с символа '/' – оно считается абсолютным. Поиск ресурса происходит следующим образом:

  1. К пути из classpath c:\work\myproject\classes приписывается имя ресурса /images/logo.png, в результате чего ищется файл c:\work\myproject\classes\images\logo.png. Если файл найден – поиск прекращается. Иначе:
  2. В jar-файле c:\lib\lib.jar ищется файл /images/logo.png, причем поиск ведется от корня jar-файла.

Пример 2. Мы используем конструкцию getClass().getResource("res/data.txt"). Поскольку имя не начинается с символа '/' – оно считается относительным. Поиск ресурса происходит следующим образом:

  1. К пути из classpath c:\work\myproject\classes приписывается текущий пакет класса, где находится код, – /ru/skipy/test, – и далее имя ресурса res/data.txt, в результате чего ищется файл c:\work\myproject\classes\ru\skipy\test\res\data.txt. Если файл найден – поиск прекращается. Иначе:
  2. В jar-файле c:\lib\lib.jar ищется файл /ru/skipy/test/res/data.txt (имя пакета текущего класса плюс имя ресурса), причем поиск ведется от корня jar-файла.

Ну и для того, чтобы ресурс был найден, необходимо обеспечить его существование. Т.е. при сборке приложения (упаковке его в jar-файл) позаботиться о том, чтобы ресурс тоже попал куда надо. Как это сделать – зависит от технологии сборки, многие IDE умеют копировать ресурсы при сборке в ту же точку, куда кладут и скомпилированные классы. При использовании ant это надо предусмотреть в явном виде.

Вот тут можно скачать полностью рабочий пример, иллюстрирующий оба типа загрузки: http://lj.skipy.ru/samples/resource_load.zip. Ресурсы – изображение и текст – располагаются в отдельной директории, при сборке попадают в jar-файл и грузятся один по абсолютному, другой по относительному имени. Пример собирается и запускается через ant, командой ant run он запускается из директории сборки build/classes/, командой ant run-jar – из собранного jar-файла.

Вот, где-то так. Вопросы? Комментарии?

Comments

skipy
Sep. 5th, 2013 08:59 am (UTC)
Можно по абсолютному пути, с '/' в начале