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
。
この投稿で場所について言及するときはいつでも、リソースのロード元のクラスやクラスローダーに応じて、ファイルシステム自体の場所、または対応するjarファイル内の場所になる可能性があります。
あなたのケースでは、アプリケーションサーバーからクラスをロードしているので、Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName)
ではなくを使用する必要がありますthis.getClass().getClassLoader().getResourceAsStream(fileName)
。this.getClass().getResourceAsStream()
も動作します。
この特定の問題に関する詳細情報については、この記事をお読みください。
Tomcat 7以下のユーザーへの警告
この質問への回答の1つに、Tomcat 7では私の説明が正しくないように見えるとあります。なぜそうなのかを調べてみました。
そこで、TomcatのWebAppClassLoader
いくつかのバージョンのTomcat のソースコードを確認しました。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つの呼び出しは常に同じ結果を返すはずです。[ソースコード]
その結果、あなたが使用している場合、余分な注意する必要がありますClassLoader.getResourceAsStream()
またはClass.getResourceAsStream()
8より前のTomcatのバージョンにそして、あなたもいることを心に留めておく必要がありclass.getResourceAsStream("/resource.txt")
、実際の呼び出しはclassLoader.getResourceAsStream("resource.txt")
(先頭が/
取り除かれます)。
getClass().getResourceAsStream("/myfile.txt")
動作が異なると確信していgetClassLoader().getResourceAsStream("/myfile.txt")
ます。