web-dev-qa-db-ja.com

Javaでリソースをロードする好ましい方法

Javaでリソースをロードする最良の方法を知りたい:

  • this.getClass().getResource() (or getResourceAsStream())
  • Thread.currentThread().getContextClassLoader().getResource(name)
  • System.class.getResource(name)
98
PomCompot

あなたが望むものに応じて解決策を考え出す...

getResource/getResourceAsStream()は、呼び出されたクラスから取得するものが2つあります...

  1. クラスローダー
  2. 出発地

もしそうなら

this.getClass().getResource("foo.txt");

「this」クラスと同じパッケージから、「this」クラスのクラスローダーでfoo.txtをロードしようとします。 「/」を前に付けると、絶対にリソースを参照していることになります。

this.getClass().getResource("/x/y/z/foo.txt")

「this」のクラスローダーとx.y.zパッケージからリソースをロードします(そのパッケージのクラスと同じディレクトリにある必要があります)。

Thread.currentThread().getContextClassLoader().getResource(name)

コンテキストクラスローダーでロードしますが、パッケージに従って名前を解決しません(絶対に参照する必要があります)

System.class.getResource(name)

システムクラスローダーでリソースを読み込みます(Java.langパッケージ(Systemのパッケージ)に何も入れることができないため、絶対に参照する必要があります)。

ソースを見てください。また、getResourceAsStreamがgetResourceから返されたURLで「openStream」を呼び出し、それを返すことを示します。

130
Michael Wiles

さて、派生クラスで実際にである場合に何をしたいのかによって部分的に異なります。

たとえば、SuperClassがA.jarにあり、SubClassがB.jarにあり、SuperClassで宣言されているがthisであるインスタンスメソッドでコードを実行するとします。 SubClassのインスタンスを参照します。 this.getClass().getResource()を使用する場合、B.jarのSubClassを基準にして表示されます。 通常は必要なものではないと思う。

個人的に私はおそらくFoo.class.getResourceAsStream(name)を最も頻繁に使用します-あなたがあなたが探しているリソースの名前をすでに知っていて、Fooに関連する場所が確かな場合、それが最も堅牢な方法ですIMOを実行します。

もちろん、それがnotである場合もあります。それぞれのケースでメリットを判断してください。 「このリソースがこのクラスにバンドルされていることを知っている」というのは、私が遭遇した最も一般的なものです。

13
Jon Skeet

次のように3つの場所を検索します。コメントを歓迎します。

public URL getResource(String resource){

    URL url ;

    //Try with the Thread Context Loader. 
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    if(classLoader != null){
        url = classLoader.getResource(resource);
        if(url != null){
            return url;
        }
    }

    //Let's now try with the classloader that loaded this class.
    classLoader = Loader.class.getClassLoader();
    if(classLoader != null){
        url = classLoader.getResource(resource);
        if(url != null){
            return url;
        }
    }

    //Last ditch attempt. Get the resource from the classpath.
    return ClassLoader.getSystemResource(resource);
}
9
dogbane

私は別の答えに本当に遅れていることを知っていますが、最後に私が助けたものを共有したかっただけです。また、クラスパスだけでなく、ファイルシステムの絶対パスからリソース/ファイルをロードします。

public class ResourceLoader {

    public static URL getResource(String resource) {
        final List<ClassLoader> classLoaders = new ArrayList<ClassLoader>();
        classLoaders.add(Thread.currentThread().getContextClassLoader());
        classLoaders.add(ResourceLoader.class.getClassLoader());

        for (ClassLoader classLoader : classLoaders) {
            final URL url = getResourceWith(classLoader, resource);
            if (url != null) {
                return url;
            }
        }

        final URL systemResource = ClassLoader.getSystemResource(resource);
        if (systemResource != null) {
            return systemResource;
        } else {
            try {
                return new File(resource).toURI().toURL();
            } catch (MalformedURLException e) {
                return null;
            }
        }
    }

    private static URL getResourceWith(ClassLoader classLoader, String resource) {
        if (classLoader != null) {
            return classLoader.getResource(resource);
        }
        return null;
    }

}
3
nyxz

上記で提案した多くの方法と機能を試しましたが、私のプロジェクトでは機能しませんでした。とにかく私は解決策を見つけましたが、ここにあります:

try {
    InputStream path = this.getClass().getClassLoader().getResourceAsStream("img/left-hand.png");
    img = ImageIO.read(path);
} catch (IOException e) {
    e.printStackTrace();
}
0
Vladislav