getResourceAsStream()とFileInputStream


173

WebアプリケーションにファイルをロードしようとしていましたがFileNotFound、を使用すると例外が発生しましたFileInputStream。しかし、同じパスを使用して、ファイルを読み込むことができましたgetResourceAsStream()。2つの方法の違いは何ですか?なぜ一方が機能し、もう一方が機能しないのですか?

回答:


256

java.io.FileそしてCONSORTSは、ローカルディスクのファイルシステムに作用します。問題の根本的な原因は、の相対パスjava.ioが現在の作業ディレクトリに依存していることです。つまり、JVM(あなたの場合:ウェブサーバーの)が起動されるディレクトリです。これは、たとえばC:\Tomcat\bin、まったく異なるものである可能性がありますが、そうでない C:\Tomcat\webapps\contextname場合、または期待どおりのものではありません。通常のEclipseプロジェクトでは、そうなりますC:\Eclipse\workspace\projectname。現在の作業ディレクトリについては、次の方法で確認できます。

System.out.println(new File(".").getAbsolutePath());

ただし、作業ディレクトリはプログラムで制御できません。APIでは相対パスではなく絶対パスを使用することをお勧めしFileます。例えばC:\full\path\to\file.ext

Java(Web)アプリケーションの絶対パスをハードコーディングしたり、推測したりする必要はありません。これは、移植性の問題のみです(つまり、システムXでは実行されますが、システムYでは実行されません)。通常は、これらの種類のリソースをclasspathに配置するか、フルパスをクラスパスに追加します(EclipseのようなIDEでは、srcフォルダーと「ビルドパス」です)。このようにして、ClassLoaderby ClassLoader#getResource()またはの助けを借りてそれらをつかむことができますClassLoader#getResourceAsStream()。偶然にわかったように、クラスパスの「ルート」に関連するファイルを見つけることができます。Webアプリケーション(または複数のクラスローダーを使用するその他のアプリケーション)では、このためClassLoaderにによって返されるを使用することをお勧めします。Thread.currentThread().getContextClassLoader()これにより、Webアプリケーションコンテキストの「外側」も確認できます。

webappsのもう1つの代替方法は、ServletContext#getResource()およびその対応物ServletContext#getResourceAsStream()です。webフォルダーを含む、webappプロジェクトのパブリックフォルダーにあるファイルにアクセスでき/WEB-INFます。ServletContext継承されたことにより、サーブレットで利用可能でgetServletContext()、あるとして、あなたがそれを呼び出すことができる、方法。

以下も参照してください。



27

getResourceAsStream (すでに学んだように)ウェブアプリでそれを行う正しい方法です。

その理由は、WebアプリをWARにパッケージ化すると、ファイルシステムからの読み取りが機能しないためです。これは、Webアプリをパッケージ化する適切な方法です。絶対ファイルパスやアプリサーバーがインストールされている場所に依存しないため、この方法で移植できます。


3
+1-「動作しない」は強すぎます。(ファイルシステムからの読み取りは機能させることができますが、移植性を高めることはトリッキーです...そして特にリソースがJARにある場合はさらに多くのコードです。)
Stephen C

1
ダッフィー、とてもいい答えとあなたは私の間違いが何であるかを説明しました、しかしBalusCは多くの詳細に行きました-私は彼の答えが同様に内部の詳細を知りたい人々のために役立つと思います。受け入れられた答えを私が変更しても構わないことを願っています!
Vivin Paliath、2010

@Stephen-「働けない」は強すぎるとは思いません。アプリサーバーへのパスが異なる2つの異なるサーバーにデプロイするような単純なものでも、問題が発生します。ポイントは、WARをできるだけ自己完結型にする必要があるということです。あなたの主張は正しいですが、私は私の言い回しに固執します。
duffymo 2010

14

FileInputStreamは、Javaプロセスの作業ディレクトリからの相対パスとして、コンストラクタに渡すファイルパスをロードします。通常、Webコンテナーでは、これはbinフォルダーのようなものです。

getResourceAsStream()アプリケーションのクラスパスからの相対ファイルパスをロードします。


12

このFileInputStreamクラスは、基になるファイルシステムと直接連携します。問題のファイルがそこに物理的に存在しない場合、ファイルを開くことができません。getResourceAsStream()この方法は、動作が異なります。ClassLoader呼び出されたクラスのを使用して、リソースを見つけてロードしようとします。これにより、たとえば、jarファイルに埋め込まれたリソースを見つけることができます。


まあ、jar内のファイルはファイルシステムに物理的に「存在」し、他のファイルに含まれているだけです
matt b

1
はい、もちろんです。しかし、アプリケーションがたまたまjarファイル形式とその影響について知らない限り、これらは通常、ファイルシステム内の独立したエンティティとは見なされません。そしてJavaでは、適切な人ClassLoaderがこの知識を持っているかもしれませんが、プレーンはFileInputStream確かに持っていません。
2010

7

classname.getResourceAsStream()は、classnameのクラスローダーを介してファイルをロードします。クラスがjarファイルからのものである場合、リソースはそこからロードされます。

FileInputStreamは、ファイルシステムからファイルを読み取るために使用されます。


0

ここでは、File Read(java.io)とResource Read(ClassLoader.getResourceAsStream())としてマークして両方の使用法を分離しています。

ファイルの読み取り-1 .ローカルファイルシステムで動作します。2.現在のJVM起動ディレクトリから要求されたファイルをrootとして見つけようとします。

リソースの読み取り -1.クラスパスで動作します。2.現在または親のクラスローダークラスパスでファイル/リソースを見つけようとします。3. warやjarなどのパッケージ化されたファイルからファイルをロードする場合に最適です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.