次の違いは何ですか?
InputStream is = this.getClass().getClassLoader().getResourceAsStream(fileName)
そして
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName)
そして
InputStream is = this.getClass().getResourceAsStream(fileName)
それぞれが他のものよりも使用するのに適しているのはいつですか?
読み取りたいファイルは、ファイルを読み取るクラスとしてクラスパスにあります。私のクラスとファイルは同じjarにあり、EARファイルにパッケージ化され、WebSphere 6.1にデプロイされています。
渡すfileName
の解釈方法には微妙な違いがあります。基本的に、2つの異なるメソッドがあります:ClassLoader.getResourceAsStream()
とClass.getResourceAsStream()
。これらの2つの方法は、リソースを異なる場所に配置します。
Class.getResourceAsStream(path)
では、パスは、呼び出し元のクラスのパッケージに対してローカルなパスとして解釈されます。たとえば、String.getResourceAsStream("myfile.txt")
を呼び出すと、クラスパス内のファイル"Java/lang/myfile.txt"
が検索されます。パスが/
で始まる場合、絶対パスと見なされ、クラスパスのルートから検索が開始されます。したがって、String.getResourceAsStream("/myfile.txt")
を呼び出すと、クラスパス./myfile.txt
の次の場所が検索されます。
ClassLoader.getResourceAsStream(path)
は、すべてのパスを絶対パスと見なします。したがって、String.getClassLoader().getResourceAsStream("myfile.txt")
とString.getClassLoader().getResourceAsStream("/myfile.txt")
を呼び出すと、クラスパスで./myfile.txt
の場所にあるファイルが検索されます。
この投稿で場所に言及するたびに、リソースの読み込み元のクラスやClassLoaderに応じて、ファイルシステム自体の場所、または対応するjarファイル内の場所になります。
あなたの場合、アプリケーションサーバーからクラスをロードしているので、Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName)
の代わりにthis.getClass().getClassLoader().getResourceAsStream(fileName)
を使用する必要があります。 this.getClass().getResourceAsStream()
も機能します。
特定の問題の詳細については、 この記事 をお読みください。
この質問に対する答えの1つに、Tomcat 7の説明が間違っているように思われると書かれています。なぜそうなるのかを調べてみました。
そこで、Tomcatのいくつかのバージョンについて、TomcatのWebAppClassLoader
のソースコードを調べました。 findResource(String name)
の実装(要求されたリソースへのURLを生成する責任を負う)は、Tomcat 6とTomcat 7で実質的に同一ですが、Tomcat 8では異なります。
バージョン6および7では、実装はリソース名の正規化を試みません。つまり、これらのバージョンでは、classLoader.getResourceAsStream("/resource.txt")
は、classLoader.getResourceAsStream("resource.txt")
イベントと同じ結果を生成しない可能性があります(Javadocで指定されているため)。 [ソースコード]
ただし、バージョン8では、リソース名は正規化され、リソース名の絶対バージョンが使用されることを保証します。したがって、Tomcat 8では、上記の2つの呼び出しは常に同じ結果を返します。 [ソースコード]
そのため、Tomcatバージョン8以前でClassLoader.getResourceAsStream()
またはClass.getResourceAsStream()
を使用する場合は、特に注意する必要があります。また、class.getResourceAsStream("/resource.txt")
は実際にclassLoader.getResourceAsStream("resource.txt")
を呼び出すことに注意する必要があります(先頭の/
は削除されます)。
MyClass.class.getClassLoader().getResourceAsStream(path)
を使用して、コードに関連付けられたリソースをロードします。 MyClass.class.getResourceAsStream(path)
をショートカットとして使用し、クラスのパッケージ内にパッケージ化されたリソースに使用します。
Thread.currentThread().getContextClassLoader().getResourceAsStream(path)
を使用して、呼び出し元コードに厳密にバインドされていないクライアントコードの一部であるリソースを取得します。スレッドコンテキストクラスローダーが何かを指している可能性があるため、これには注意が必要です。
プレーンオールドJava 7のプレーンオールドJava 7および他の依存関係は違いを示しません...
file.txt
をc:\temp\
に配置し、c:\temp\
をクラスパスに配置します。
2つの呼び出しに違いがある場合は1つだけです。
class J {
public static void main(String[] a) {
// as "absolute"
// ok
System.err.println(J.class.getResourceAsStream("/file.txt") != null);
// pop
System.err.println(J.class.getClassLoader().getResourceAsStream("/file.txt") != null);
// as relative
// ok
System.err.println(J.class.getResourceAsStream("./file.txt") != null);
// ok
System.err.println(J.class.getClassLoader().getResourceAsStream("./file.txt") != null);
// no path
// ok
System.err.println(J.class.getResourceAsStream("file.txt") != null);
// ok
System.err.println(J.class.getClassLoader().getResourceAsStream("file.txt") != null);
}
}
ここでのこれらすべての答えと この質問 の答えは、「/ foo/bar.properties」のような絶対URLのロードがclass.getResourceAsStream(String)
とclass.getClassLoader().getResourceAsStream(String)
によって同じように扱われることを示唆しています。少なくとも私のTomcat構成/バージョン(現在7.0.40)ではそうではありません。
MyClass.class.getResourceAsStream("/foo/bar.properties"); // works!
MyClass.class.getClassLoader().getResourceAsStream("/foo/bar.properties"); // does NOT work!
申し訳ありませんが、満足のいく説明はまったくありませんが、Tomcatはクラスローダーで汚いトリックと彼の黒魔術を行い、違いを引き起こしていると思います。過去にclass.getResourceAsStream(String)
を使用していましたが、問題はありませんでした。
PS:私もこれを投稿しました here
成功せずにファイルをロードするいくつかの方法を試した後、私はFileInputStream
を使用できたことを思い出しました。
InputStream is = new FileInputStream("file.txt");
これは、ファイルをInputStream
に読み込む別の方法で、現在実行中のフォルダーからファイルを読み取ります。