web-dev-qa-db-ja.com

Java JARファイル内のリソースへのパスを取得する方法

リソースへのパスを取得しようとしていますが、運がありません。

これは機能します(IDEとJARの両方)が、この方法ではファイルへのパスを取得できず、ファイルの内容のみが取得できます。

ClassLoader classLoader = getClass().getClassLoader();
PrintInputStream(classLoader.getResourceAsStream("config/netclient.p"));

これを行う場合:

ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource("config/netclient.p").getFile());

結果は次のとおりです。Java.io.FileNotFoundException: file:/path/to/jarfile/bot.jar!/config/netclient.p (No such file or directory)

リソースファイルへのパスを取得する方法はありますか?

151
no_ripcord

これは意図的なものです。 「ファイル」の内容は、ファイルとして利用できない場合があります。 JARファイルまたは他の種類のリソースの一部である可能性のあるクラスとリソースを扱っていることに注意してください。クラスローダーは、リソースにファイルハンドルを提供する必要はありません。たとえば、jarファイルはファイルシステム内の個々のファイルに展開されていない場合があります。

Java.io.Fileが絶対に必要な場合、Java.io.Fileを取得することでできることはすべて、ストリームを一時ファイルにコピーして同じことを行うことができます。

68
Neal Maloney

リソースをロードするときは、次の違いに注意してください。

getClass().getClassLoader().getResource("com/myorg/foo.jpg") //relative path

そして

getClass().getResource("/com/myorg/foo.jpg")); //note the slash at the beginning

この混乱は、リソースをロードするときにほとんどの問題を引き起こしていると思います。


また、画像を読み込むときは、getResourceAsStream()を使用する方が簡単です:

BufferedImage image = ImageIO.read(getClass().getResourceAsStream("/com/myorg/foo.jpg"));

本当にJARアーカイブから(非イメージ)ファイルをロードする必要がある場合、これを試してみてください。

    File file = null;
    String resource = "/com/myorg/foo.xml";
    URL res = getClass().getResource(resource);
    if (res.getProtocol().equals("jar")) {
        try {
            InputStream input = getClass().getResourceAsStream(resource);
            file = File.createTempFile("tempfile", ".tmp");
            OutputStream out = new FileOutputStream(file);
            int read;
            byte[] bytes = new byte[1024];

            while ((read = input.read(bytes)) != -1) {
                out.write(bytes, 0, read);
            }
            out.close();
            file.deleteOnExit();
        } catch (IOException ex) {
            Exceptions.printStackTrace(ex);
        }
    } else {
        //this will probably work in your IDE, but not from a JAR
        file = new File(res.getFile());
    }

    if (file != null && !file.exists()) {
        throw new RuntimeException("Error: File " + file + " not found!");
    }
53
Tombart

一行の答えは-

String path = this.getClass().getClassLoader().getResource(<resourceFileName>).toExternalForm()

基本的にgetResourceメソッドはURLを提供します。このURLから、toExternalForm()を呼び出してパスを抽出できます

参照:

getResource()toExternalForm()

20

私はこの問題をいじくり回しましたが、実際には解決策が見つからなかったので、奇妙なことに十分です!多くの場合、作業ディレクトリはJARのディレクトリではありません。特に、Windowsの[スタート]メニューからJAR(または任意のプログラム)を実行する場合はそうです。だからここに私がやったことがあり、それはJARの場合と同様に、JARの外部から実行される.classファイルに対しても機能します。 (Windows 7でのみテストしました。)

try {
    //Attempt to get the path of the actual JAR file, because the working directory is frequently not where the file is.
    //Example: file:/D:/all/Java/TitanWaterworks/TitanWaterworks-en.jar!/TitanWaterworks.class
    //Another example: /D:/all/Java/TitanWaterworks/TitanWaterworks.class
    PROGRAM_DIRECTORY = getClass().getClassLoader().getResource("TitanWaterworks.class").getPath(); // Gets the path of the class or jar.

    //Find the last ! and cut it off at that location. If this isn't being run from a jar, there is no !, so it'll cause an exception, which is fine.
    try {
        PROGRAM_DIRECTORY = PROGRAM_DIRECTORY.substring(0, PROGRAM_DIRECTORY.lastIndexOf('!'));
    } catch (Exception e) { }

    //Find the last / and cut it off at that location.
    PROGRAM_DIRECTORY = PROGRAM_DIRECTORY.substring(0, PROGRAM_DIRECTORY.lastIndexOf('/') + 1);
    //If it starts with /, cut it off.
    if (PROGRAM_DIRECTORY.startsWith("/")) PROGRAM_DIRECTORY = PROGRAM_DIRECTORY.substring(1, PROGRAM_DIRECTORY.length());
    //If it starts with file:/, cut that off, too.
    if (PROGRAM_DIRECTORY.startsWith("file:/")) PROGRAM_DIRECTORY = PROGRAM_DIRECTORY.substring(6, PROGRAM_DIRECTORY.length());
} catch (Exception e) {
    PROGRAM_DIRECTORY = ""; //Current working directory instead.
}
11
DeProgrammer

netclient.pがJARファイル内にある場合、そのファイルは他のファイル内にあるため、パスはありません。その場合、使用できる最適なパスは、実際にはfile:/path/to/jarfile/bot.jar!/config/netclient.pです。

8
cd1

Jarファイル内のパスを理解する必要があります。
単に相対的なものを指します。したがって、\src\main\resourcesディレクトリの下のfoo.jarにあるファイル(myfile.txt)がある場合(Mavenスタイル)。次のように参照します。

src/main/resources/myfile.txt

jar -tvf myjar.jarを使用してjarをダンプすると、jarファイル内に出力と相対パスが表示され、FORWARD SLASHESが使用されます。

6
eric manley

これは、jarリソースからの不完全な一時ファイルコンテンツコピーを回避し、一意の一時ファイル名を持つために、ストリームフラッシュとクローズを使用するユーザーTombartの同じコードです。

     File file = null;
        String resource = "/view/Trial_main.html" ;
        URL res = getClass().getResource(resource);
        if (res.toString().startsWith("jar:")) {
            try {
                InputStream input = getClass().getResourceAsStream(resource);
                file = File.createTempFile(new Date().getTime()+"", ".html");
                OutputStream out = new FileOutputStream(file);
                int read;
                byte[] bytes = new byte[1024];

                while ((read = input.read(bytes)) != -1) {
                    out.write(bytes, 0, read);
                }
                out.flush();
                out.close();
                input.close();
                file.deleteOnExit();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        } else {
            //this will probably work in your IDE, but not from a JAR
            file = new File(res.getFile());
        }
2
Bruce

私の場合、PathではなくURLオブジェクトを使用しました。

ファイル

File file = new File("my_path");
URL url = file.toURI().toURL();

クラスローダーを使用したクラスパスのリソース

URL url = MyClass.class.getClassLoader().getResource("resource_name")

コンテンツを読む必要があるときは、次のコードを使用できます。

InputStream stream = url.openStream();

また、InputStreamを使用してコンテンツにアクセスできます。

2
jmgoyesc

ファイルはファイルシステム内のファイルの抽象化であり、ファイルシステムはJARの内容について何も知りません。

URIで試してください。あなたの目的に役立つjar://プロトコルがあると思います。

2
fortran

Jarのressourcesフォルダー(Java/main/resources)にファイルを追加します(imports.xmlという名前のxmlファイルを追加したと仮定します) )、その後、次のようなスプリングを使用する場合はResourceLoaderを注入します

@Autowired
private ResourceLoader resourceLoader;

ツアー機能内で、ファイルをロードするために以下のコードを記述します。

    Resource resource = resourceLoader.getResource("classpath:imports.xml");
    try{
        File file;
        file = resource.getFile();//will load the file
...
    }catch(IOException e){e.printStackTrace();}
private static final String FILE_LOCATION = "com/input/file/somefile.txt";

//Method Body


InputStream invalidCharacterInputStream = URLClassLoader.getSystemResourceAsStream(FILE_LOCATION);

これをgetSystemResourceAsStreamから取得するのが最適なオプションです。ファイルまたはURLではなく入力ストリームを取得することにより、JARファイル内でスタンドアロンとして機能します。

1
Shano

少し遅いかもしれませんが、私のライブラリ KResourceLoader を使用して、jarからリソースを取得できます。

File resource = getResource("file.txt")
1
Lamberto Basti

次のパスは私のために働いた:classpath:/path/to/resource/in/jar

1
Anatoly

Jarファイルの場合、リソースは絶対にパッケージ階層にあります(ファイルシステム階層ではありません)。したがって、「./ default.conf」という名前のリソースをロードするクラスcom.example.Sweetがある場合、リソースの名前は「/com/example/default.conf」として指定されます。

しかし、それが瓶に入っている場合、それはファイルではありません...

0
Vilnis Krumins

述べられているように、これはリソースをロードする最適な方法ではありませんが、Java.io.File参照が絶対に必要な場合は、次を試してください:

 URL url = null;
  try {
     URL baseUrl = YourClass.class.getResource(".");
     if (baseUrl != null) {
        url = new URL(baseUrl, "yourfilename.ext");
     } else {
        url = YourClass.class.getResource("yourfilename.ext");
     }
  } catch (MalformedURLException e) {
     // Do something appropriate
  }

これによりJava.net.URLが得られ、Java.io.Fileコンストラクターで使用できます。

0
Jes

たぶん、この方法は迅速な解決に使用できます。

public static String getResourcePath(String relativePath)
{
    String pathStr = null;
    URL location = <Class>.class.getProtectionDomain().getCodeSource().getLocation();
    String codeLoaction = location.toString();
    try{
        if (codeLocation.endsWith(".jar"){
            //Call from jar
            Path path = Paths.get(location.toURI()).resolve("../classes/" + relativePath).normalize();
            pathStr = path.toString();
        }else{
            //Call from IDE
            pathStr = <Class>.class.getClassLoader().getResource(relativePath).getPath();
        }
    }catch(URISyntaxException ex){
        ex.printStackTrace();
    }
    return pathStr;
}
0
gbii