サーチ…


前書き

Javaでは、コンパイルされたクラスと一緒にJARの内部に格納されているファイルベースのリソースを取得できます。このトピックでは、これらのリソースをロードし、コードで使用できるようにすることに重点を置いています。

備考

リソースとは、パスのような名前のファイルのようなデータで、クラスパスに存在します。リソースの最も一般的な使用方法は、アプリケーションイメージ、サウンド、および読み取り専用データ(デフォルト設定など)をバンドルすることです。

リソースを使ってアクセスすることができClassLoader.getResourceClassLoader.getResourceAsStream方法。最も一般的な使用例は、リソースを読み取るクラスと同じパッケージに配置することです。 Class.getResourceClass.getResourceAsStream方法は、この一般的な使用例を提供しています。

getResourceメソッドとgetResourceAsStreamメソッドの唯一の違いは、前者がURLを返し、後者がそのURLを開き、InputStreamを返すことです。

ClassLoaderのメソッドは、パスのようなリソース名を引数として受け取り、その名前に一致するエントリをClassLoaderのクラスパス内の各位置で検索します。

  • クラスパスの場所が.jarファイルの場合、指定された名前のjarエントリは一致とみなされます。
  • クラスパスの場所がディレクトリの場合、指定された名前を持つそのディレクトリの下の相対ファイルは一致と見なされます。

リソース名は、相対URLのパス部分に似ています。 すべてのプラットフォームで、ディレクトリ区切り文字としてスラッシュ( / )を使用します。スラッシュで始めることはできません。

Classの対応するメソッドは、以下を除いて同様です。

  • リソース名はスラッシュで始まり、その場合は最初のスラッシュが削除され、残りの名前はClassLoaderの対応するメソッドに渡されます。
  • リソース名がスラッシュで始まらない場合は、getResourceメソッドまたはgetResourceAsStreamメソッドが呼び出されているクラスに対して相対的な名前として扱われます。実際のリソース名は、 パッケージは、パッケージの名前であるパッケージ / 名前となるクラスはスラッシュで置き換え各周期で、所属、 名前がメソッドに渡さ元引数されます。

例えば:

package com.example;

public class ExampleApplication {
    public void readImage()
    throws IOException {

        URL imageURL = ExampleApplication.class.getResource("icon.png");

        // The above statement is identical to:
        // ClassLoader loader = ExampleApplication.class.getClassLoader();
        // URL imageURL = loader.getResource("com/example/icon.png");

        Image image = ImageIO.read(imageURL);
    }
}

リソースは、クラスがパッケージに置かれるのと同じ理由で、.jarファイルのルートではなく、名前付きパッケージに配置する必要があります。たとえば、複数の.jarファイルがクラスパス内にあり、複数の.jarファイルがルートにconfig.propertiesエントリを含む場合、getResourceメソッドまたはgetResourceAsStreamメソッドを呼び出すと、最初にリストされている.jarからconfig.propertiesが返されますクラスパスJava EEのように、クラスパス順序がアプリケーションの直接の制御下にない環境では、これは予測可能な動作ではありません。

すべてのgetResourceおよびgetResourceAsStreamメソッドは、指定されたリソースが存在しない場合はnull返しnull 。ビルド時にアプリケーションにリソースを追加する必要があるため、コードが書き込まれるときにリソースの位置を知る必要があります。実行時にリソースを見つけることができないのは、通常、プログラマーのエラーの結果です。

リソースは読み取り専用です。リソースに書き込む方法はありません。初心者の開発者は、IDE(Eclipseなど)で開発するときにリソースが別の物理ファイルであるため、一般的なケースでは別の物理ファイルのように扱うことが安全であると仮定して間違いを犯すことがよくあります。しかし、これは正しくありません。アプリケーションはほとんどの場合、.jarまたは.warファイルなどのアーカイブとして配布されます。そのような場合、リソースは個別のファイルではなく、書き込み可能ではありません。 (URLクラスのgetFileメソッドはこれを回避する方法ではなく 、名前にもかかわらずURLのパス部分を返すだけであり、これは決して有効なファイル名であることは保証されません)。

実行時にリソースをリストする安全な方法はありません。ここでも、開発者はビルド時にリソースファイルをアプリケーションに追加する責任があるため、開発者は既にそのパスを知っているはずです。回避策がありますが、信頼性がなく、最終的には失敗します。

リソースからイメージをロードする

バンドルされたイメージをロードするには:

package com.example;

public class ExampleApplication {
    private Image getIcon() throws IOException {
        URL imageURL = ExampleApplication.class.getResource("icon.png");
        return ImageIO.read(imageURL);
    }
}

デフォルト設定の読み込み

デフォルトの構成プロパティーを読み取るには:

package com.example;

public class ExampleApplication {
    private Properties getDefaults() throws IOException {
        Properties defaults = new Properties();

        try (InputStream defaultsStream =
            ExampleApplication.class.getResourceAsStream("config.properties")) {

            defaults.load(defaultsStream);
        }

        return defaults;
    }
}

複数のJARから同じ名前のリソースをロードする

同じパスと名前を持つリソースは、クラスパス上の複数のJARファイルに存在する可能性があります。一般的なケースは、慣習に従ったリソースまたはパッケージ仕様の一部であるリソースです。そのようなリソースの例は次のとおりです。

  • META-INF / MANIFEST.MF
  • META-INF / beans.xml(CDI仕様)
  • 実装プロバイダを含むServiceLoaderプロパティ

別の瓶でこれらのすべてのリソースへのアクセスを得るためには、このためのメソッドを持つクラスローダを使用する必要があります。返されたEnumerationは、Collections関数を使用してList簡単に変換できます。

Enumeration<URL> resEnum = MyClass.class.getClassLoader().getResources("META-INF/MANIFEST.MF");
ArrayList<URL> resources = Collections.list(resEnum);

クラスローダーを使用したリソースの検索と読み取り

Javaでのリソースのロードは、次の手順で構成されます。

  1. リソースを見つけるClassまたはClassLoader検索。
  2. リソースを見つける。
  3. リソースのバイトストリームを取得します。
  4. バイトストリームの読み取りと処理。
  5. バイトストリームを閉じます。

最後の3つのステップは、通常、URLをライブラリメソッドまたはコンストラクタに渡してリソースをロードすることによって実現されます。通常、この場合はgetResourceメソッドを使用しgetResource 。アプリケーションコード内のリソースデータを読み取ることもできます。通常、この場合はgetResourceAsStreamを使用しgetResourceAsStream

絶対および相対リソースパス

クラスパスからロードできるリソースは、パスで示されます 。パスの構文は、UNIX / Linuxファイルパスに似ています。スラッシュ( / )文字で区切られた単純な名前で構成されています。 相対パスは名前で始まり、 絶対パスはセパレータで始まります。

クラスパスの例で説明しているように、JVMのクラスパスは、クラスパスにディレクトリとJARまたはZIPファイルの名前空間をオーバーレイすることによって名前空間を定義します。絶対パスが解決されると、クラスローダーは最初の/を名前空間のルートを意味するものとして解釈します。対照的に、相対パス名前空間内の任意の「フォルダ」に対して解決される可能性があります。使用されるフォルダは、パスを解決するために使用するオブジェクトによって異なります。

クラスまたはクラスローダの取得

リソースは、 ClassオブジェクトまたはClassLoaderオブジェクトのいずれかを使用してClassLoaderます。 Classオブジェクトは相対パスを解決することができるため、(クラス)相対リソースがある場合は、通常はこれらのいずれかを使用します。 Classオブジェクトを取得するにはさまざまな方法があります。例えば:

  • クラスリテラルは、Javaソースコードで名前を付けることができる任意のクラスのClassオブジェクトを提供します。例えばString.classString型のClassオブジェクトを提供します。

  • Object.getClass()は、任意のオブジェクトタイプのClassオブジェクトを提供します。例えば"hello".getClass()は、 String型のClassを取得する別の方法です。

  • Class.forName(String)メソッドは(必要に応じて)クラスを動的にロードし、そのClassオブジェクトを返します。例: Class.forName("java.lang.String")

ClassLoaderオブジェクトは、通常、 Classオブジェクトに対してgetClassLoader()を呼び出すことによって取得されます。静的なClassLoader.getSystemClassLoader()メソッドを使用して、JVMのデフォルトクラスローダーを取得することもできます。

getメソッド

ClassまたはClassLoaderインスタンスをClassLoaderたら、次のいずれかの方法でリソースを見つけることができます。

メソッド説明
ClassLoader.getResource(path)
ClassLoader.getResources(path)
指定されたパスを持つリソースの場所を表すURLを返します。
ClassLoader.getResources(path)
Class.getResources(path)
foo.barリソースの検索に使用できるURLを示すEnumeration<URL>を返します。下記参照。
ClassLoader.getResourceAsStream(path)
Class.getResourceStream(path)
foo.barリソースの内容を一連のバイトとして読み取ることができるInputStreamを返します。

ノート:

  • ClassLoaderClassバージョンのメソッドの主な違いは、相対パスが解釈される方法です。

    • Classメソッドは、クラスパッケージに対応する "フォルダ"内の相対パスを解決します。
    • ClassLoaderメソッドは、相対パスを絶対パスとして扱います。つまり、クラスパス名前空間の "ルートフォルダ"でそれらを解決します。
  • 要求されたリソース(またはリソース)が見つからない場合、 getResourceおよびgetResourceAsStream methods return nullをmethods return , and the getResources methods return an empty Enumeration`をmethods return an emptyます。

  • 返されるURLは、 URL.toStream()を使用して解決できます。それらはfile: URLや他の従来のURLでもかまいませんが、リソースがJARファイルにある場合、JARファイルとその中の特定のリソースを識別するjar: URLになります。

  • コードがgetResourceAsStreamメソッド(またはURL.toStream() )を使用してInputStreamを取得する場合は、ストリームオブジェクトを閉じる必要があります。ストリームを閉じないと、リソースがリークする可能性があります。



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow