수색…


소개

Java는 컴파일 된 클래스와 함께 JAR 내부에 저장된 파일 기반 리소스를 검색 할 수 있습니다. 이 항목에서는 이러한 리소스를로드하고 코드에서 사용할 수 있도록하는 방법에 대해 중점적으로 설명합니다.

비고

자원 은 클래스 경로에 상주하는 경로와 같은 이름을 가진 파일과 유사한 데이터입니다. 가장 일반적인 리소스 사용은 응용 프로그램 이미지, 사운드 및 읽기 전용 데이터 (기본 구성 등)를 번들로 묶는 것입니다.

ClassLoader.getResourceClassLoader.getResourceAsStream 메소드를 사용하여 리소스에 액세스 할 수 있습니다. 가장 일반적인 사용 사례는 리소스를 읽는 클래스와 동일한 패키지에 배치하는 것입니다. Class.getResourceClass.getResourceAsStream 메소드는이 일반적인 사용 사례를 제공합니다.

getResource 메소드와 getResourceAsStream 메소드의 유일한 차이점은 전자는 URL을 리턴하고, 후자는 URL을 열고 InputStream을 리턴한다는 것입니다.

ClassLoader의 메소드는 경로와 같은 자원 이름을 인수로 사용하고 ClassLoader 클래스 경로의 각 위치에서 해당 이름과 일치하는 항목을 검색합니다.

  • 클래스 패스의 장소가. jar 파일의 경우, 지정된 이름을 가지는 jar 엔트리는 매치로 간주됩니다.
  • 클래스 경로 위치가 디렉토리 인 경우 지정된 이름을 가진 해당 디렉토리 아래의 상대 파일은 일치로 간주됩니다.

리소스 이름은 상대 URL의 경로 부분과 비슷합니다. 모든 플랫폼에서 디렉토리 분리 기호로 슬래시 ( / )를 사용합니다. 슬래시로 시작하면 안됩니다.

Class의 대응하는 메소드는 다음과 같습니다.

  • 자원 명은 슬래시 (slash)로 시작할 수 있으며,이 경우 처음 슬래시는 제거되고 나머지 이름은 ClassLoader의 해당 메소드로 전달됩니다.
  • 자원 이름이 슬래시로 시작하지 않으면 getResource 또는 getResourceAsStream 메소드가 호출되는 클래스와 관련하여 처리됩니다. 실제 자원 이름은 package / name이됩니다 . 여기서 package 는 클래스가 속한 패키지의 이름이고 각 마침표는 슬래시로 대체되며 name 은 메소드에 제공된 원래 인수입니다.

예를 들면 :

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 메소드를 호출하면 처음에 나열된 .jar에서 config.properties가 반환됩니다. classpath. 클래스 경로 순서가 Java EE와 같이 응용 프로그램을 직접 제어하지 않는 환경에서는 예측할 수없는 동작입니다.

지정된 자원이 존재하지 않는 경우, 모든 getResource 및 getResourceAsStream 메소드는 null 리턴합니다. 빌드시 응용 프로그램에 자원을 추가해야하므로 코드 작성시 해당 위치를 알려야합니다. 런타임에 자원을 찾을 수 없으면 일반적으로 프로그래머 오류가 발생합니다.

리소스는 읽기 전용입니다. 리소스에 쓸 수있는 방법이 없습니다. 초보자 개발자는 IDE (Eclipse와 같은)에서 개발할 때 자원이 별도의 실제 파일이므로 일반적으로 개별 물리적 파일처럼 취급하는 것이 안전하다고 가정합니다. 그러나 이것은 올바르지 않습니다. 응용 프로그램은 거의 항상 .jar 또는 .war 파일과 같은 아카이브로 배포됩니다.이 경우 자원은 별도의 파일이 아니며 쓰기가 불가능합니다. URL 클래스의 getFile 메서드는이 문제 를 해결하는 방법이 아니며 , 이름에도 불구하고 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 스펙)
  • 구현 공급자를 포함하는 ServiceLoader 속성

다른 항아리에있는 이러한 모든 리소스에 액세스하려면 ClassLoader를 사용해야합니다. ClassLoader에는이를위한 메소드가 있습니다. 반환되는 Enumeration 은 Collections 함수를 사용하여 편리하게 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 객체를 얻는 방법에는 여러 가지가 있습니다. 예 :

  • 클래스 리터럴 은 Java 소스 코드에서 이름을 지정할 수있는 모든 클래스의 Class 객체를 제공합니다. 예 : String.classString 유형의 Class 객체를 제공합니다.

  • Object.getClass() 는 임의의 객체 유형에 대한 Class 객체를 제공합니다. 예 : "hello".getClass()String 유형의 Class 를 가져 오는 또 다른 방법입니다.

  • Class.forName(String) 메소드는 (필요한 경우) 클래스를 동적으로로드하고 Class 객체를 리턴합니다. 예 : Class.forName("java.lang.String") .

ClassLoader 객체는 일반적으로 Class 객체에서 getClassLoader() 를 호출하여 가져 getClassLoader() . 정적 ClassLoader.getSystemClassLoader() 메소드를 사용하여 JVM의 기본 클래스 로더를 확보 할 수도 있습니다.

get 메소드

Class 또는 ClassLoader 인스턴스가 있으면 다음 방법 중 하나를 사용하여 리소스를 찾을 수 있습니다.

행동 양식 기술
ClassLoader.getResource(path)
ClassLoader.getResources(path)
지정된 패스를 가지는 자원의 위치를 ​​나타내는 URL를 돌려줍니다.
ClassLoader.getResources(path)
Class.getResources(path)
foo.bar 리소스를 찾는 데 사용할 수있는 URL을 제공하는 Enumeration<URL> 을 반환합니다. 아래를보십시오.
ClassLoader.getResourceAsStream(path)
Class.getResourceStream(path)
foo.bar 리소스의 내용을 일련의 바이트로 읽을 수있는 InputStream 을 반환합니다.

노트:

  • ClassLoaderClass 버전의 메소드 간의 주요 차이점은 상대 경로가 해석되는 방식입니다.

    • Class 메서드는 클래스 패키지에 해당하는 "폴더"의 상대 경로를 확인합니다.
    • ClassLoader 메소드는 상대 경로가 절대 경로 인 것처럼 처리합니다. 즉, 클래스 경로 네임 스페이스의 "루트 폴더"에서이를 해결하십시오.
  • 요청 된 자원 (또는 자원)을 찾을 수없는 경우 getResource 및 getResourceAsStream methods return null을 methods return , and the getResources methods return an empty Enumeration`을 methods return an empty .

  • 반환 된 URL은 URL.toStream() 사용하여 해석 할 수 있습니다. 그들은 수 file: URL 또는 다른 기존의 URL을하지만, 자원이 JAR 파일에있는 경우, 그들은 것 jar: JAR 파일과 내의 특정 자원을 식별하는 URL.

  • 코드가 getResourceAsStream 메소드 (또는 URL.toStream() )를 사용하여 InputStream 을 얻는 경우 스트림 객체를 닫아야합니다. 스트림을 닫지 않으면 자원이 누출 될 수 있습니다.



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow