[java] getResourceAsStream은 null을 반환

Java 프로젝트의 컴파일 된 JAR의 패키지 내에서 텍스트 파일을로드하고 있습니다. 관련 디렉토리 구조는 다음과 같습니다.

/src/initialization/Lifepaths.txt

내 코드는를 Class::getResourceAsStream반환하기 위해 호출 하여 파일을로드 합니다 InputStream.

public class Lifepaths {
    public static void execute() {
        System.out.println(Lifepaths.class.getClass().
            getResourceAsStream("/initialization/Lifepaths.txt"));
    }

    private Lifepaths() {}

    //This is temporary; will eventually be called from outside
    public static void main(String[] args) {execute();}
}

인쇄물은 null내가 무엇을 사용하든 항상 인쇄 합니다. 위의 방법이 작동하지 않는 이유를 잘 모르겠으므로 시도해 보았습니다.

  • "/src/initialization/Lifepaths.txt"
  • "initialization/Lifepaths.txt"
  • "Lifepaths.txt"

이 둘 중 어느 것도 작동하지 않습니다. 나는 한 읽고 많은 질문을 지금까지 주제에,하지만 그들 중 누구도 도움이 없었다 – 보통, 그들은 단지 이미하고 있어요 루트 경로를 사용하여로드 파일을 말한다. 또는 현재 디렉토리에서 파일을로드 (로드 만하면됩니다 filename). 내도 시도했습니다. 파일이 적절한 이름으로 적절한 위치에있는 JAR로 컴파일됩니다.

이 문제를 어떻게 해결합니까?



답변

Lifepaths.class.getClass().getResourceAsStream(...) 시스템 클래스 로더를 사용하여 리소스를로드하면 JAR이 표시되지 않기 때문에 분명히 실패합니다.

Lifepaths.class.getResourceAsStream(...) Lifepaths 클래스를로드 한 것과 동일한 클래스 로더를 사용하여 자원을로드하며 JAR의 자원에 액세스해야합니다.


답변

규칙은 다음과 같습니다.

  1. JAR 내부에로드 할 파일의 위치를 ​​확인하십시오 (따라서 실제로 JAR에 추가되었는지 확인하십시오)
  2. 절대 경로를 사용하십시오. 경로는 JAR의 루트에서 시작합니다.
  3. 상대 경로를 사용하십시오 : 경로는 getResource / getResoucreAsStream을 호출하는 클래스의 패키지 디렉토리에서 시작합니다

그리고 시도하십시오 :

Lifepaths.class.getResourceAsStream("/initialization/Lifepaths.txt")

대신에

Lifepaths.class.getClass().getResourceAsStream("/initialization/Lifepaths.txt")

(차이가 있는지 확실하지 않지만 전자는 올바른 ClassLoader / JAR을 사용하지만 후자는 확실하지 않습니다)


답변

따라서 jar에서 리소스를 가져 오는 여러 가지 방법이 있으며 경로를 다르게 지정 해야하는 구문이 약간 다릅니다.

내가 본 가장 좋은 설명은 JavaWorld 의이 기사입니다 . 여기에 요약하지만 더 알고 싶다면 기사를 확인하십시오.

행동 양식

1) ClassLoader.getResourceAsStream().

형식 : “/”로 구분 된 이름; 선행 “/”없음 (모든 이름은 절대적 임)

예: this.getClass().getClassLoader().getResourceAsStream("some/pkg/resource.properties");

2) Class.getResourceAsStream()

형식 : “/”로 구분 된 이름; 선행 “/”는 절대 이름을 나타냅니다. 다른 모든 이름은 클래스 패키지와 관련이 있습니다.

예: this.getClass().getResourceAsStream("/some/pkg/resource.properties");


답변

절대 경로를 사용하지 말고 프로젝트의 ‘resources’디렉토리를 기준으로하십시오. ‘resources’디렉토리에서 MyTest.txt의 내용을 표시하는 빠르고 더러운 코드입니다.

@Test
public void testDefaultResource() {
    // can we see default resources
    BufferedInputStream result = (BufferedInputStream)
         Config.class.getClassLoader().getResourceAsStream("MyTest.txt");
    byte [] b = new byte[256];
    int val = 0;
    String txt = null;
    do {
        try {
            val = result.read(b);
            if (val > 0) {
                txt += new String(b, 0, val);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    } while (val > -1);
    System.out.println(txt);
}


답변

스트림을 얻으려면 이것을 시도하십시오. 즉, 먼저 URL을 얻은 다음 스트림으로여십시오.

URL url = getClass().getResource("/initialization/Lifepaths.txt");
InputStream strm = url.openStream(); 

한 번 비슷한 질문이있었습니다 : jar에서 txt 파일을 읽는 데 실패하지만 이미지를 읽는 것이 좋습니다.


답변

사용중인 ClassLoader에 문제가있는 것 같습니다. contextClassLoader를 사용하여 클래스를로드하십시오. 정적 / 비 정적 방법인지 여부에 관계없이

Thread.currentThread().getContextClassLoader().getResourceAsStream……


답변

나는 비슷한 문제에서 나 자신을 발견했다. maven을 사용하고 있기 때문에 다음과 같은 내용을 포함하도록 pom.xml을 업데이트해야했습니다.

   ...
</dependencies>
<build>
    <resources>
        <resource>
            <directory>/src/main/resources</directory>
        </resource>
        <resource>
            <directory>../src/main/resources</directory>
        </resource>
    </resources>
    <pluginManagement>
        ...

해당 폴더의 위치를 ​​지정하려면 여기에 리소스 태그를 기록하십시오. 중첩 된 프로젝트가있는 경우 (내가하는 것처럼) 작업중인 모듈이 아닌 다른 영역에서 리소스를 가져오고 싶을 수 있습니다. 유사한 구성 데이터를 사용하는 경우 각 리포지토리에서 동일한 파일을 유지하는 데 도움이됩니다.