getResourceAsStreamはnullを返します


183

Javaプロジェクトのコンパイル済みJARのパッケージ内からテキストファイルをロードしています。関連するディレクトリ構造は次のとおりです。

/src/initialization/Lifepaths.txt

私のコードはClass::getResourceAsStreamを返すように呼び出してファイルをロードしますInputStream

public class Lifepaths {
    public static void execute() {
        System.out.println(Lifepaths.class.getClass().
            getResourceAsStream("/initialization/Lifepaths.txt"));
    }

    private Lifepaths() {}

    //This is temporary; will eventually be called from outside
    public static void main(String[] args) {execute();}
}

null何を使用しても、印刷は常に印刷されます。上記がうまくいかない理由がわからないので、私も試しました:

  • "/src/initialization/Lifepaths.txt"
  • "initialization/Lifepaths.txt"
  • "Lifepaths.txt"

これらはどちらも機能しません。私は これまでにこのトピックに関して数多くの質問読み ましたが、どれも役に立たなかった-通常、彼らは単に私がすでに行っているルートパスを使用してファイルをロードするように言うだけです。または、現在のディレクトリからファイルをロードするだけです(単にload )。ファイルは、適切な場所に適切な名前でJARにコンパイルされています。 filename

どうすればこれを解決できますか?


3
あなたはそれが本当にいることを確認しましたある jarファイルに?ファイルのケーシングを確認しましたか?
ジョンスキート2013年

@JonSkeet確かに適切な場所にあるJARファイルにコンパイルされており、大文字と小文字は正しいです。

1
@greedybuddha静的コンテキストから呼び出すことはできませんが、を使用して呼び出すことができLifepaths.classます。とはgetClassLoader()いえ、なぜ機能するのですか?(また、お気軽に回答を投稿してください!)

見せてもらえますLifepaths.getClass()か?Objectにはそのような静的メソッドは定義されていません...
Puce

1
見ていこの回答を&あなたはそれを使用して作業を取得することができます参照してくださいgetResource(String)。ところで-私は常にこれらのいずれかをstaticコンテキストで機能させるのに問題がありました。問題は基本的に、取得したクラスローダーがJ2SEクラス向けのものであることです。アプリケーション自体を対象としたコンテキストクラスローダーにアクセスする必要があります。
Andrew Thompson

回答:


159

Lifepaths.class.getClass().getResourceAsStream(...) システムクラスローダーを使用してリソースをロードします。JARを認識しないため、明らかに失敗します

Lifepaths.class.getResourceAsStream(...) Lifepathsクラスをロードしたのと同じクラスローダーを使用してリソースをロードし、JARのリソースにアクセスできる必要があります


129
付け加えると、getResourceAsStream(name)を呼び出すとき、名前は「/」で始まる必要があります。これが必要かどうかはわかりませんが、それがなければ問題があります。
デビッド

3
私はこれを昨日の午前8時からねじ込んでいます。助かりました。それを機能させるには、先頭にスラッシュも必要でした。
kyle

4
また、目的のソースがパッケージ階層の外にある可能性があることにも注意してください。この場合、パスに「../」を使用して1つのレベルに到達し、次に別のパスブランチに到達してリソースに到達する必要があります。
ゾーン

3
@David-(先頭の '/')が必要だと思います。それ以外の場合は、Lifepaths.classパッケージに関連して検索します
Mz A

5
情報を追加する/だけで、ファイルが別のディレクトリにある場合は、パスの前にを追加する必要があります。例えばinitialization/Lifepaths.txt。ファイルのパスがyoutクラスと同じである(ただし、メインディレクトリとしてのリソースの下にある)場合は、なしでファイルの名前を指定できます/。たとえば、クラスに次のパスがあるsrc/main/java/paths/Lifepaths.java場合、ファイルにはこのパスが必要src/main/resources/paths/Lifepaths.txtです。
ドウィッツ2018

59

ルールは次のとおりです。

  1. JAR内でロードするファイルの場所を確認します(したがって、実際にJARに追加されていることも確認してください)。
  2. 絶対パスを使用:パスはJARのルートから始まります
  3. 相対パスを使用:パスは、getResource / getResoucreAsStreamを呼び出しているクラスのパッケージディレクトリから始まります。

そして試してください:

Lifepaths.class.getResourceAsStream("/initialization/Lifepaths.txt")

の代わりに

Lifepaths.class.getClass().getResourceAsStream("/initialization/Lifepaths.txt")

(違いがあるかどうかはわかりませんが、前者は正しいClassLoader / JARを使用しますが、後者はわかりません)


2
私はこれらの3つすべてをすでに実行しました。私の質問をもう一度読んでください。

あなたの質問からは、「関連するディレクトリ構造」が何であるか、およびファイルがJAR内にあるかどうか、およびその場所を実際に確認したかどうかはわかりません(ステップ1)
Puce

1
相対パスについてのあなたの発言は、私の終わりにようやく問題を解決しました。ありがとう!
ポールボルマンス

面白い。それは...私はそれを取得するために(スラッシュ)「/config.properties」をしなければならなかったが判明
Erkを

45

したがって、jarからリソースを取得するにはいくつかの方法があり、それぞれにパスが異なるように指定する必要があるわずかに異なる構文があります。

私が見た中で最も良い説明は、JavaWorldからのこの記事です。ここでまとめますが、もっと知りたい場合は、記事をチェックしてください。

方法

1)ClassLoader.getResourceAsStream()

形式:「/」で区切られた名前。先頭に "/"はありません(すべての名前は絶対名です)。

例: this.getClass().getClassLoader().getResourceAsStream("some/pkg/resource.properties");

2) Class.getResourceAsStream()

形式:「/」で区切られた名前。先頭の「/」は絶対名を示します。他のすべての名前はクラスのパッケージに関連しています

例: this.getClass().getResourceAsStream("/some/pkg/resource.properties");


2番目の例は壊れています
Janus Troelsen

1
2番目の例は、リソースの場所に依存する答えで述べたように、壊れていません。
greedybuddha 2016

また、ソースフォルダーを更新して、IDEがファイル( 'some / pkg / resource.properties')を認識していることを確認してください。
Eric Duminil、

15

絶対パスは使用せず、プロジェクトの「resources」ディレクトリからの相対パスにしてください。ディレクトリ 'resources'のMyTest.txtの内容を表示する素早くて汚いコード。

@Test
public void testDefaultResource() {
    // can we see default resources
    BufferedInputStream result = (BufferedInputStream) 
         Config.class.getClassLoader().getResourceAsStream("MyTest.txt");
    byte [] b = new byte[256];
    int val = 0;
    String txt = null;
    do {
        try {
            val = result.read(b);
            if (val > 0) {
                txt += new String(b, 0, val);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } 
    } while (val > -1);
    System.out.println(txt);
}

9

これを試してストリームを取得することもできます。つまり、最初にURLを取得してから、それをストリームとして開きます。

URL url = getClass().getResource("/initialization/Lifepaths.txt"); 
InputStream strm = url.openStream(); 

私は以前に同様の質問をしました:jarからのtxtファイルの読み取りは失敗しますが、画像の読み取りは機能します


3
これは、まさにgetResourceAsStream()が行うことです
fedeb

8

使用しているClassLoaderに問題があるようです。contextClassLoaderを使用してクラスをロードします。これは、それが静的/非静的メソッドであるかどうかに関係ありません

Thread.currentThread().getContextClassLoader().getResourceAsStream……


6

私も同様の問題を抱えていました。私はmavenを使用しているので、pom.xmlを更新して次のようなものを含める必要がありました。

   ...
</dependencies>
<build>
    <resources>
        <resource>
            <directory>/src/main/resources</directory>
        </resource>
        <resource>
            <directory>../src/main/resources</directory>
        </resource>
    </resources>
    <pluginManagement>
        ...

そこにあるリソースタグに注意して、そのフォルダーの場所を指定してください。ネストされたプロジェクトがある場合(私と同じように)、作業中のモジュールだけでなく、他の領域からリソースを取得することをお勧めします。これにより、同様の構成データを使用している場合に、各リポジトリに同じファイルを保持するのを減らすことができます


3

どのような私のために働いたことの下でファイルを追加することでしたMy Project/Java Resources/srcし、その後の使用

this.getClass().getClassLoader().getResourceAsStream("myfile.txt");

このファイルを明示的にパスに追加する必要はありませんでした(追加するように追加し/srcているようです)


誤ったJava構文
Ilya Kharlamov 2017年

2

ヘルプがあるかどうかわかりませんが、私の場合、/ src /フォルダーにリソースがあり、このエラーが発生していました。次に、画像をbinフォルダーに移動し、問題を修正しました。


2

リソースディレクトリ(「src」など)がクラスパスにあることを確認してください(Eclipseのビルドパスのソースディレクトリであることを確認してください)。

clazzがメインのクラスローダーから読み込まれていることを確認します。

次に、src / initialization / Lifepaths.txtをロードするには、次を使用します

clazz.getResourceAsStream("/initialization/Lifepaths.txt");

理由: clazz.getResourcesAsStream(foo)からのfooアップルックスclazzのクラスパス内にはディレクトリclazzに相対に住んでいます。先頭の「/」は、clazzのクラスパス内の任意のディレクトリのルートからロードします。

Tomcatのようなコンテナにいる場合や、直接ClassLoadersで何かをしている場合を除き、eclipse /コマンドラインクラスパスを唯一のクラスローダークラスパスとして扱うことができます。


2

デフォルトのJVMクラスローダーは、親クラスローダーを使用して最初にリソースをロードします deletegate-parent-classloader

Lifepaths.class.getClass()のクラスローダーはbootstrap classloaderなのでgetResourceAsStream、指定されたユーザーに関係なく、$ JAVA_HOMEのみを検索しますclasspath。明らかに、Lifepaths.txtはありません。

Lifepaths.classのクラスローダーはsystem classpath classloaderなので、getResourceAsStreamユーザー定義classpathでLifepaths.txtが検索されます。

を使用する場合java.lang.Class#getResourceAsStream(String name)「/」で始まらない名前はpackage name接頭辞として追加されます。これを避けたい場合はをご利用くださいjava.lang.ClassLoader#getResourceAsStream。例えば:

ClassLoader loader = Thread.currentThread().getContextClassLoader();
String resourceName = "Lifepaths.txt";
InputStream resourceStream = loader.getResourceAsStream(resourceName); 

2

大ざっぱに言えば:

getClass().getResource("/") 〜= Thread.currentThread().getContextClassLoader().getResource(".")

プロジェクトの構造が次のようであるとします。

├── src
   ├── main
   └── test
   └── test
       ├── java
          └── com
              └── github
                  └── xyz
                      └── proj
                          ├── MainTest.java
                          └── TestBase.java
       └── resources
           └── abcd.txt
└── target
    └── test-classes
        ├── com
        └── abcd.txt
// in MainClass.java
this.getClass.getResource("/") -> "~/proj_dir/target/test-classes/"
this.getClass.getResource(".") -> "~/proj_dir/target/test-classes/com/github/xyz/proj/"
Thread.currentThread().getContextClassLoader().getResources(".") -> "~/proj_dir/target/test-classes/"
Thread.currentThread().getContextClassLoader().getResources("/") ->  null

2

Mavenを使用している場合は、パッキングが「pom」ではなく「jar」であることを確認してください。

<packaging>jar</packaging>

0

本当に必要なのは、ファイルの完全な絶対パスです。だから、それを推測するのではなく、ルートを見つけて、ファイルを1つの<.war>ファイル構造に基づいてより適切な場所に移動してください...

URL test1 = getClass().getResource("/");
URL test2 = getClass().getClassLoader().getResource("/");            
URL test3 = getClass().getClassLoader().getResource("../");

logger.info(test1.getPath()); 
logger.info(test2.getPath());
logger.info(test3.getPath());

0

私にとってうまくいったのは、ファイルを

src/main/java/myfile.log

そして

InputStream is = getClass().getClassLoader().getResourceAsStream("myfile.log");
        
        if (is == null) {
            throw new FileNotFoundException("Log file not provided");
        }

ソースフォルダーはと呼ばれsrc/main/JAVA、非コードファイルはここに配置しないでください。
レイレン

-12

@Emracool ...私はあなたに代替案をお勧めします。* .txtファイルをロードしようとしているようです。FileInputStream()この迷惑なgetClass().getClassLoader().getResourceAsStream()またはよりむしろ使用する方が良いgetClass().getResourceAsStream()。少なくとも、コードは正しく実行されます。


何 ???そのような実用的な答えの場合は-1。何があっても。しかし、上記の解決策は確実に機能します。
Jain
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.