web-dev-qa-db-ja.com

ファイルをInputStreamとしてロードするさまざまな方法

次の違いは何ですか?

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にデプロイされています。

203
zqudlyba

渡す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()も機能します。

特定の問題の詳細については、 この記事 をお読みください。


Tomcat 7以下のユーザーに対する警告

この質問に対する答えの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")を呼び出すことに注意する必要があります(先頭の/は削除されます)。

279
LordOfThePigs

MyClass.class.getClassLoader().getResourceAsStream(path)を使用して、コードに関連付けられたリソースをロードします。 MyClass.class.getResourceAsStream(path)をショートカットとして使用し、クラスのパッケージ内にパッケージ化されたリソースに使用します。

Thread.currentThread().getContextClassLoader().getResourceAsStream(path)を使用して、呼び出し元コードに厳密にバインドされていないクライアントコードの一部であるリソースを取得します。スレッドコンテキストクラスローダーが何かを指している可能性があるため、これには注意が必要です。

20

プレーンオールドJava 7のプレーンオールドJava 7および他の依存関係は違いを示しません...

file.txtc:\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); 
  }
}
5
John Lonergan

ここでのこれらすべての答えと この質問 の答えは、「/ 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

3
Tim Büthe

成功せずにファイルをロードするいくつかの方法を試した後、私はFileInputStreamを使用できたことを思い出しました。

InputStream is = new FileInputStream("file.txt");

これは、ファイルをInputStreamに読み込む別の方法で、現在実行中のフォルダーからファイルを読み取ります。

0
Toni Almeida