Поиск…


Вступление

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 включает следующие шаги:

  1. Поиск Class или ClassLoader , который найдет ресурс.
  2. Поиск ресурса.
  3. Получение байтового потока для ресурса.
  4. Чтение и обработка байтового потока.
  5. Закрытие байтового потока.

Последние три шага обычно выполняются путем передачи 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 и getResourceAsStream methods return null , and the methods return an empty getResources methods return an empty перечисление.

  • URL.toStream() URL-адреса будут URL.toStream() с помощью URL.toStream() . Они могут быть file: URL-адресами или другими обычными URL-адресами, но если ресурс находится в JAR-файле, они будут jar: URL-адресами, которые идентифицируют JAR-файл и определенный ресурс внутри него.

  • Если ваш код использует метод getResourceAsStream (или URL.toStream() ) для получения InputStream , он отвечает за закрытие объекта потока. Невозможность закрыть поток может привести к утечке ресурсов.



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow