Javaでリソースをロードする最良の方法を知りたいです。
this.getClass().getResource() (or getResourceAsStream())
、Thread.currentThread().getContextClassLoader().getResource(name)
、System.class.getResource(name)
。
Javaでリソースをロードする最良の方法を知りたいです。
this.getClass().getResource() (or getResourceAsStream())
、Thread.currentThread().getContextClassLoader().getResource(name)
、System.class.getResource(name)
。回答:
必要に応じてソリューションを作成してください...
getResource
/ getResourceAsStream()
が呼び出されたクラスから/ が取得するものは2つあります...
だからあなたがするなら
this.getClass().getResource("foo.txt");
「this」クラスと同じパッケージから、「this」クラスのクラスローダーを使用してfoo.txtをロードしようとします。「/」を前に置くと、リソースを完全に参照していることになります。
this.getClass().getResource("/x/y/z/foo.txt")
「this」のクラスローダーとxyzパッケージからリソースを読み込みます(パッケージ内のクラスと同じディレクトリにある必要があります)。
Thread.currentThread().getContextClassLoader().getResource(name)
コンテキストクラスローダーでロードされますが、パッケージに従って名前を解決しません(絶対参照する必要があります)
System.class.getResource(name)
システムクラスローダーを使用してリソースをロードします(java.langパッケージ(システムのパッケージ)に何も入れることができないため、絶対的に参照する必要もあります)。
ソースを見てください。また、getResourceAsStreamがgetResourceから返されたURLで「openStream」を呼び出し、それを返すことも示しています。
Thread#setContextClassLoader
。これは、プログラムの実行中にクラスパスを変更する必要がある場合に役立ちます。
まあ、実際に派生クラスにいる場合に何をしたいかによっても異なります。
たとえば、SuperClass
がA.jarとSubClass
B.jarにありSuperClass
、で宣言されているインスタンスメソッドでコードを実行しているが、はのthis
インスタンスを参照しているとしますSubClass
。使用this.getClass().getResource()
するとSubClass
、B.jarではに相対的に見えます。それは通常必要なことではないようです。
個人的に私はおそらくFoo.class.getResourceAsStream(name)
最も頻繁に使用します-あなたが探しているリソースの名前をすでに知っていて、それがとの相対位置がわかっている場合は、それがFoo
IMOを実行する最も堅牢な方法です。
もちろん、それが望ましくない場合もあります。それぞれのケースをそのメリットで判断してください。「このリソースがこのクラスにバンドルされていることを知っている」というのは、私が遭遇した最も一般的なものです。
this.getClass()
ます。サブクラスのインスタンスを作成してメソッドを呼び出すと、スーパークラスではなくサブクラスの名前が出力されます。
以下のように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);
}
私は別の答えが本当に遅いのを知っていますが、私が最後に私を助けたものを共有したかっただけです。また、(クラスパスだけでなく)ファイルシステムの絶対パスからリソース/ファイルをロードします。
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;
}
}
上記の方法や機能をたくさん試しましたが、私のプロジェクトではうまくいきませんでした。とにかく私は解決策を見つけました、そしてそれはここにあります:
try {
InputStream path = this.getClass().getClassLoader().getResourceAsStream("img/left-hand.png");
img = ImageIO.read(path);
} catch (IOException e) {
e.printStackTrace();
}
this.getClass().getResourceAsStream()
この場合は、より適切に使用する必要があります。getResourceAsStream
メソッドのソースを見ると、それがあなたと同じことをしていることに気づくでしょう。ClassLoader
行われていることがわかりますクラスに見つから)。また、あなたは可能性が発生する可能性があることを示しているnull
にgetClassLoader
...あなたのコードで
this.getClass().getResourceAsStream()
ように私のために働いていないので、私はそれがうまくいくように使用します。私のような問題に直面できる人もいると思います。