Java Language
Ресурсы (на пути к классам)
Поиск…
Вступление
Java позволяет извлекать файловые ресурсы, хранящиеся внутри JAR, вместе с скомпилированными классами. В этом разделе основное внимание уделяется загрузке этих ресурсов и обеспечению их доступности для вашего кода.
замечания
Ресурс - это файловые данные с именем типа пути, которое находится в пути к классам. Наиболее частое использование ресурсов - это объединение изображений приложений, звуков и данных только для чтения (таких как конфигурация по умолчанию).
Доступ к ресурсам можно получить с помощью методов ClassLoader.getResource и ClassLoader.getResourceAsStream . Наиболее распространенным случаем является наличие ресурсов, размещенных в том же пакете, что и класс, который их читает; методы Class.getResource и Class.getResourceAsStream служат этому обычному варианту использования.
Единственное различие между методом getResource и методом getResourceAsStream заключается в том, что первый возвращает URL-адрес, а второй открывает этот URL-адрес и возвращает InputStream.
Методы ClassLoader принимают имя типа пути как аргумент и ищут каждое местоположение в пути класса ClassLoader для записи, соответствующей этому имени.
- Если местоположение класса является файлом .jar, запись в jar с указанным именем считается совпадением.
- Если расположение пути к классам является каталогом, относительный файл в этом каталоге с указанным именем считается совпадением.
Имя ресурса похоже на часть пути относительного URL. На всех платформах он использует косые черты ( /
) в качестве разделителей каталогов. Он не должен начинаться с косой черты.
Соответствующие методы класса аналогичны, за исключением:
- Имя ресурса может начинаться с косой черты, и в этом случае начальная косая черта удаляется, а остальная часть имени передается соответствующему методу ClassLoader.
- Если имя ресурса не начинается с косой черты, оно рассматривается как относительное к классу, вызываемому методом getResource или getResourceAsStream. Фактическое имя ресурса становится package / name , где package - это имя пакета, к которому принадлежит класс, причем каждый период заменяется косой чертой, а имя - исходным аргументом, заданным для метода.
Например:
package com.example;
public class ExampleApplication {
public void readImage()
throws IOException {
URL imageURL = ExampleApplication.class.getResource("icon.png");
// The above statement is identical to:
// ClassLoader loader = ExampleApplication.class.getClassLoader();
// URL imageURL = loader.getResource("com/example/icon.png");
Image image = ImageIO.read(imageURL);
}
}
Ресурсы должны размещаться в именованных пакетах, а не в корневом каталоге .jar, по той же причине классы помещаются в пакеты: Чтобы предотвратить столкновение между несколькими поставщиками. Например, если несколько файлов .jar находятся в пути к классам, и более чем один из них содержит запись config.properties
в своем корне, вызовы методов getResource или getResourceAsStream возвращают параметры config.properties из того, что .jar указан первым в путь к классам. Это не предсказуемое поведение в средах, где порядок пути к классам не находится под непосредственным контролем приложения, например Java EE.
Все методы getResource и getResourceAsStream возвращают значение null
если указанный ресурс не существует. Поскольку ресурсы должны быть добавлены в приложение во время сборки, их местоположения должны быть известны при написании кода; отказ найти ресурс во время выполнения обычно является результатом ошибки программиста.
Ресурсы доступны только для чтения. Невозможно написать ресурс. Разработчики новичка часто ошибаются, полагая, что, поскольку ресурс является отдельным физическим файлом при разработке в среде IDE (например, Eclipse), безопасно рассматривать его как отдельный физический файл в общем случае. Однако это неверно; приложения почти всегда распространяются как архивы, такие как файлы .jar или .war, и в таких случаях ресурс не будет отдельным файлом и не будет доступен для записи. (Метод getFile для класса URL-адресов не является обходным путем для этого, несмотря на его имя, он просто возвращает часть пути URL-адреса, которая отнюдь не гарантирует, что это действительное имя файла).
Не существует безопасного способа перечислить ресурсы во время выполнения. Опять же, поскольку разработчики несут ответственность за добавление файлов ресурсов в приложение во время сборки, разработчики должны уже знать их пути. Хотя есть обходные пути, они не надежны и в конечном итоге потерпят неудачу.
Загрузка изображения с ресурса
Чтобы загрузить связанное изображение:
package com.example;
public class ExampleApplication {
private Image getIcon() throws IOException {
URL imageURL = ExampleApplication.class.getResource("icon.png");
return ImageIO.read(imageURL);
}
}
Загрузка конфигурации по умолчанию
Чтобы прочитать свойства конфигурации по умолчанию:
package com.example;
public class ExampleApplication {
private Properties getDefaults() throws IOException {
Properties defaults = new Properties();
try (InputStream defaultsStream =
ExampleApplication.class.getResourceAsStream("config.properties")) {
defaults.load(defaultsStream);
}
return defaults;
}
}
Загрузка одноименного ресурса из нескольких JAR
Ресурс с одним и тем же путем и именем может существовать в более чем одном JAR-файле в пути к классам. Обычными случаями являются ресурсы, следующие за конвенцией, или которые являются частью спецификации упаковки. Примерами таких ресурсов являются
- META-INF / MANIFEST.MF
- META-INF / beans.xml (CDI Spec)
- Свойства ServiceLoader, содержащие поставщиков реализации
Чтобы получить доступ ко всем этим ресурсам в разных банках, нужно использовать ClassLoader, у которого есть метод для этого. Возвращаемое Enumeration
можно удобно преобразовать в List
с помощью функции «Коллекции».
Enumeration<URL> resEnum = MyClass.class.getClassLoader().getResources("META-INF/MANIFEST.MF");
ArrayList<URL> resources = Collections.list(resEnum);
Поиск и чтение ресурсов с помощью загрузчика классов
Загрузка ресурсов в Java включает следующие шаги:
- Поиск
Class
илиClassLoader
, который найдет ресурс. - Поиск ресурса.
- Получение байтового потока для ресурса.
- Чтение и обработка байтового потока.
- Закрытие байтового потока.
Последние три шага обычно выполняются путем передачи URL-адреса библиотечному методу или конструктору для загрузки ресурса. В этом случае вы обычно будете использовать метод getResource
. Также возможно считывать данные ресурсов в коде приложения. В этом случае вы обычно будете использовать getResourceAsStream
.
Абсолютные и относительные пути ресурсов
Ресурсы , которые могут быть загружены из пути к классам, обозначены пути. Синтаксис пути похож на путь файла UNIX / Linux. Он состоит из простых имен, разделенных символами прямой косой черты ( /
). Относительный путь начинается с имени, а абсолютный путь начинается с разделителя.
Как описывают примеры Classpath, путь к классам JVM определяет пространство имен путем наложения пространств имен каталогов и JAR или ZIP-файлов в пути к классам. Когда абсолютный путь разрешен, он загрузчик классов интерпретирует исходный /
как смысл корня пространства имен. Напротив, относительный путь может быть разрешен относительно любой «папки» в пространстве имен. Используемая папка будет зависеть от объекта, который используется для разрешения пути.
Получение класса или загрузчика классов
Ресурс может быть расположен с использованием объекта Class
или объекта ClassLoader
. Объект Class
может разрешать относительные пути, поэтому вы обычно используете один из них, если у вас есть (класс) относительный ресурс. Существует множество способов получить объект Class
. Например:
Литерал класса даст вам объект
Class
для любого класса, который вы можете назвать в исходном коде Java; напримерString.class
предоставляет объектClass
для типаString
.Object.getClass()
предоставит вам объектClass
для типа od любого объекта; например,"hello".getClass()
- это еще один способ получитьClass
типаString
.Метод
Class.forName(String)
будет (при необходимости) динамически загружать класс и возвращать его объектClass
; напримерClass.forName("java.lang.String")
.
Объект ClassLoader
обычно получается путем вызова getClassLoader()
объекта Class
. Также можно получить загрузчик классов по умолчанию JVM, используя статический ClassLoader.getSystemClassLoader()
.
Методы get
Если у вас есть экземпляр Class
или ClassLoader
, вы можете найти ресурс, используя один из следующих способов:
методы | Описание |
---|---|
ClassLoader.getResource(path) ClassLoader.getResources(path) | Возвращает URL-адрес, который представляет местоположение ресурса с заданным путем. |
ClassLoader.getResources(path) Class.getResources(path) | Возвращает Enumeration<URL> указывающее URL-адреса, которые можно использовать для поиска ресурса foo.bar ; увидеть ниже. |
ClassLoader.getResourceAsStream(path) Class.getResourceStream(path) | Возвращает InputStream из которого вы можете прочитать содержимое ресурса foo.bar в виде последовательности байтов. |
Заметки:
Основное различие между версиями методов
ClassLoader
иClass
заключается в том, как интерпретируются относительные пути.- Методы
Class
разрешают относительный путь в папке, соответствующей пакету классов. - Методы
ClassLoader
обрабатывают относительные пути, как если бы они были абсолютными; т.е. разрешить их в «корневой папке» пространства имен classpath.
- Методы
Если запрошенный ресурс (или ресурсы) не может быть найден,
methods return
getResource
и getResourceAsStreammethods return
null, and the
methods return an empty
getResourcesmethods return an empty
перечисление.URL.toStream()
URL-адреса будутURL.toStream()
с помощьюURL.toStream()
. Они могут бытьfile:
URL-адресами или другими обычными URL-адресами, но если ресурс находится в JAR-файле, они будутjar:
URL-адресами, которые идентифицируют JAR-файл и определенный ресурс внутри него.Если ваш код использует метод
getResourceAsStream
(илиURL.toStream()
) для полученияInputStream
, он отвечает за закрытие объекта потока. Невозможность закрыть поток может привести к утечке ресурсов.