Проблема с Java getResourceAsStream, путаница с тем, как работают пакеты - PullRequest
0 голосов
/ 21 мая 2019

Я возвращаюсь к Java после краткого изучения его в старшей школе, чтобы работать с lwjgl git book .Есть раздел, который как бы теряет меня, где фрагментный шейдер / вершинный шейдер должен быть загружен с использованием функции 'getResourceAsStream'.

Я пробовал разные подходы и тщетно пытался отладить / распечатать местагде JVM искала файл, но я немного растерялся.Я очень запутался, но также предпочел бы понять, почему этот код не работает на моей машине, и как заставить его работать (с этим подходом к загрузке пакетов / классов).

Поскольку оба класса совместно используюткласс 'main', я думал, что JVM будет искать там, начиная с папки 'resources'.Но, похоже, это не так.

Я действительно думаю, что это связано с объявлениями пакетов, но я не понимаю достаточно, чтобы продолжить.

Вот соответствующие файлы иместоположения ... Я пытался включить только то, что мне показалось важным.

// project-root/src/main/java/org/lwjglb/engine/Utils.java

package main.java.org.lwjglb.engine;
// other imports...
public class Utils {
    public static String loadResource(String fileName) {
    InputStream in = class.forName(Utils.class.getName()).getResourceAsStream(fileName);
    // 'in' is null after this call
    // other code...
    }
}
// project-root/src/main/java/org/lwjglb/game/Renderer.java

import main.java.org.lwjgl.engine.Utils;
// other imports...
public class Renderer {
    public void init() {
        Utils.loadResource("/vertex.vs"); // fails
    }
}
// project-root/src/main/resources/vertex.vs

// vertex shader code...

Проблема в том, что вызов getResourceAsStream () возвращает значение null, поэтому следующий код, который зависит от действительногоВ результате происходит сбой с java.lang.NullPointerException.

Какой путь мне следует передать getResourceAsStream (), чтобы он не возвращал ноль?

Ответы [ 2 ]

1 голос
/ 21 мая 2019

Предположим следующую структуру каталогов:

|-- src
    `-- test
        |-- java
        |   `-- shaders
        |       `-- ShaderParser.java
        `-- resources
            `-- shaders
                `-- fragmentShader.txt

Правильный способ получить ресурс «fragShader.txt» из «ShaderParser.java»:

Class clazz = Class.forName(TestUtils.class.getName());
InputStream in = clazz.getResourceAsStream("../../resources/shaders/fragmentShader.txt");

../ означает «перейти вверх на один каталог». Путь начинается в каталоге src/test/java/shaders/, поэтому мы используем ../../, чтобы дважды пройти вверх в src/test/, а затем привязать остальную часть нашего пути resources/shaders/fragmentShader.txt.

Важно помнить, что при использовании Class # getResourceAsStream () он использует пакет, в котором находится класс, в качестве базового каталога. Он ONLY использует относительные пути, потому что он пытается загрузить ресурс, используя этот класс ' ClassLoader . и не будет работать, если указан полный путь или путь, начинающийся с корня проекта.

Для получения дополнительной информации см. Документацию .

0 голосов
/ 25 мая 2019

Я ошибочно думал, что у Java есть зарезервированный каталог (например, «ресурсы»), куда он сначала будет загружать файлы. Вид похож на Flask в питоне.

Однако теперь я понимаю, что функция class.getResourceAsStream () принимает относительные пути (к текущему пакету «самого низкого» уровня) или абсолютные пути (от корня верхнего уровня проекта).

Более того, я ошибочно думал, что могу попробовать сделать относительную загрузку пути из одного из пакетов более высокого уровня. Например, я нахожусь в пакете main.java.org.lwjgl.engine.Utils, но при поиске файла main.resources.vertex.vs я мог бы начать поиск из пакета 'main' и передать 'resources / vertex.vs 'или' resources / vertex.vs '. Я не знаю, возможно ли это, но это кажется ошибочным.

Вместо этого решение состоит в том, чтобы передать местоположение файла '/main/resources/vertex.vs'. Это запустится в корне проекта и правильно загрузит файл.

Я все еще не понимаю, как работает код lwjgl , но я вижу, что вполне возможно, что для classPath установлено значение 'main', поэтому передача абсолютного пути может сработать.

...