web-dev-qa-db-ja.com

getResourceAsStreamがnullを返す

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

/src/initialization/Lifepaths.txt

ファイルのロードに使用されているコードは次のとおりです。

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"

どちらもうまくいきません。 私は読んでたくさんいますこれまでのところ質問 は役に立ちませんでしたが、どれも役に立ちませんでした。私はすでに行っているルートパスを使用します。それか、単に現在のディレクトリからファイルをロードするだけです(単にfilenameをロードする)。これも私が試してみました。ファイルは適切な場所で適切な名前でJARにコンパイルされています。

どうやってこれを解決できますか?

143
Aza

Lifepaths.class.getClass().getResourceAsStream(...)はシステムクラスローダを使ってリソースをロードしますが、JARが見えないので明らかに失敗します

Lifepaths.class.getResourceAsStream(...)はLifepathsクラスをロードしたのと同じクラスローダーを使用してリソースをロードします。それはあなたのJAR内のリソースにアクセスできるはずです

133
hoaz

規則は次のとおりです。

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

そして試してみてください。

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

の代わりに

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

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

52
Puce

そのため、jarからリソースを取得するにはいくつかの方法がありますが、それぞれパスの指定が異なる必要がある場合は構文が若干異なります。

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

方法

1)ClassLoader.getResourceAsStream()

フォーマット:「/」で区切られた名前。先頭に "/"は付きません(すべての名前は絶対パスです)。

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

2)Class.getResourceAsStream()

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

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

42
greedybuddha

絶対パスを使用しないでください。プロジェクト内の '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);
}
13
Paul Smith

あなたは、ストリームを取得するためにこれを試してみたいかもしれません。すなわち、最初にURLを取得し、それからストリームとしてそれを開くことです。

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

私はかつて同じような質問をしました: jarからのtxtファイルの読み込みは失敗しますが、画像の読み込みはうまくいきます

9
MrD

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

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

7
Binita Bharati

助けになるかどうかわからないが、私の場合私のリソースは/ src /フォルダにあり、このエラーが出ていた。それから写真をbinフォルダに移動して問題を解決しました。

2
Leo Ufimtsev

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

Clazzがメインのクラスローダーからロードされていることを確認してください。

それから、src/initialization/Lifepaths.txtをロードするために、

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

理由:clazz.getResourcesAsStream(foo)clazzのクラスパス内clazzが存在するディレクトリからの相対パス _からfooを検索します。先頭に "/"を付けると、clazzのクラスパス内の任意のディレクトリのルートからロードされます。

Tomcatのようなある種のコンテナにいるのではないか、ClassLoaderで直接何かをしているのでない限り、あなたのEclipse /コマンドラインクラスパスを唯一のクラスローダクラスパスとして扱うことができます。

2
Bobby Martin

私は同じような問題に自分自身を見つけました。私はmavenを使っているので、pom.xmlを更新して次のようなものを含める必要がありました。

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

そこにあるリソースタグをメモして、そのフォルダがどこにあるかを指定します。ネストしたプロジェクトがある場合(私のように)、作業中のモジュール内ではなく、他の領域からリソースを入手したい場合があります。これは、同じリポジトリーデータを使用している場合、各リポジトリで同じファイルを保持する手間を省きます。

1
plosco

私の場合、ファイル名からスペースを削除しない限り、何も機能しませんでした。

0
user3563159

私にとってうまくいったのは、My Project/Java Resources/srcにファイルを追加してから、

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

このファイルをパスに明示的に追加する必要はありません(/ srcに追加すると、明らかに行われます)。

0
CommonCoreTawan

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

Lifepaths.class.getClass()のクラスローダーはbootstrap classloaderなので、getResourceAsStreamはユーザーが提供したclasspathに関係なく、$ Java_HOMEのみを検索します。明らかに、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); 
0
ridox