jarファイル内からリソース「フォルダー」を取得するにはどうすればよいですか?


139

プロジェクトのルートにリソースフォルダ/パッケージがありますが、特定のファイルをロードしたくないのです。特定のファイルをロードしたい場合は、class.getResourceAsStreamを使用すれば問題ありません。私が実際にしたいことは、リソースフォルダー内の「フォルダー」をロードし、そのフォルダー内のファイルをループし、各ファイルへのストリームを取得してコンテンツを読み取ることです...実行前にファイル名が決定されていないと仮定します。 ... 私は何をすべきか?あなたのjarファイルのフォルダ内のファイルのリストを取得する方法はありますか?リソースを含むJarファイルは、コードの実行元のJARファイルと同じであることに注意してください...

前もって感謝します...


1
これは役立つだろう:stackoverflow.com/questions/1529611/...
Jigarジョシ


5
最初の1つは、jarファイルを抽出することです。これは、たとえば、状況が悪化した場合など、私が試してみたい最後のことです。ファイルを抽出したい場合は、インストール時にファイルをインストールフォルダーに配置します。jar内からそれらにアクセスしたいのですが、私の理由は、getResourceAsStreamがファイルにアクセスできる場合、Javaはそのjar内のフォルダを抽出する必要なく探せるはずです。しかし、ありがとう...
Mostafa Zeinali

回答:


111

最後に、私は解決策を見つけました:

final String path = "sample/folder";
final File jarFile = new File(getClass().getProtectionDomain().getCodeSource().getLocation().getPath());

if(jarFile.isFile()) {  // Run with JAR file
    final JarFile jar = new JarFile(jarFile);
    final Enumeration<JarEntry> entries = jar.entries(); //gives ALL entries in jar
    while(entries.hasMoreElements()) {
        final String name = entries.nextElement().getName();
        if (name.startsWith(path + "/")) { //filter according to the path
            System.out.println(name);
        }
    }
    jar.close();
} else { // Run with IDE
    final URL url = Launcher.class.getResource("/" + path);
    if (url != null) {
        try {
            final File apps = new File(url.toURI());
            for (File app : apps.listFiles()) {
                System.out.println(app);
            }
        } catch (URISyntaxException ex) {
            // never happens
        }
    }
}

2番目のブロックは、IDEで(jarファイルではなく)アプリケーションを実行したときに機能します。それが気に入らない場合は削除できます。


正解を更新しました。これは私がやりたいことではありませんが、特に34000以上のソースファイルを含むコードでは...しかし、それが唯一の解決策のようです。ありがとうございました。
Mostafa Zeinali

4
ちなみに、getPathはサーバーのドメインに関連するものを返すため、webstartから起動した場合は機能しません。
amos

1
パスがjar内にある場合は機能しないと考えてください。toURI変換でこのエラーが発生します:java.lang.IllegalArgumentException:URIは階層的ではありません
トリビロイド

4
単一のjarファイルに対してのみ機能し、別のjarの依存関係からリソースを抽出するようには機能しません
三倍体

2
1.これは、.jarファイルが同じシステム上のローカルファイルであると想定しています。2. URL.getPath()は有効なファイル名を返さず、パーセントエスケープをすべてそのままにして、URLのパス部分を返すだけです。3. ProtectionDomain.getCodeSource()はnullを返すことができます
VGR 2017年

14

以下を試してください。 たとえば、クラスパスがcom.abc.package.MyClassで、リソースファイルがsrc / com / abc / package / resources /内にある場合
は、リソースパスを"<PathRelativeToThisClassFile>/<ResourceDirectory>"作成します。

URL url = MyClass.class.getResource("resources/");
if (url == null) {
     // error - missing folder
} else {
    File dir = new File(url.toURI());
    for (File nextFile : dir.listFiles()) {
        // Do something with nextFile
    }
}

あなたも使うことができます

URL url = MyClass.class.getResource("/com/abc/package/resources/");

27
お手数をおかけして申し訳ありませんが、.jarファイル内にコードベースがあり、リソースもその.jarファイルにある場合、これは機能しません。.jarファイル内にいるときは、File()を作成できず、そのフォルダーのURLも取得できません...私は個人的にそれで問題なく、各ファイルをXMLにリストしました...私はしませんjarファイル内のフォルダーに対して、それができると思います...
Mostafa Zeinali

2
問題が発生してすみません。ただし、コードベースがjarファイル内にあり、リソースもそのjarファイル内にある場合、実際には機能します。あなたはディスク上にFile()を作成していません-jarファイル内のファイルをJavaメモリに読み込んでいます。ClassLoaderは、ディスク上のディレクトリと同等のjarファイルを処理して問題ないことに注意してください。ここでは、ソースからの詳細です:
グレンベスト

1
jarでコードを実行すると、エラーが発生します。V申し訳ありませんが、私の悪いです。「File:...!/ dir1 / dir2 ...」でjar URLパスを処理する必要があります。2つの修正:stackoverflow.com/questions/1429172/… またはString jarPath = dirURL.getPath()。substring(5、dirURL.getPath()。indexOf( "!")); JarFile jar = new JarFile(URLDecoder.decode(jarPath、 "UTF-8")); Enumeration <JarEntry>エントリ= jar.entries(); while(entries.hasMoreElements()){//何かをする}
Glen Best

3
javadocから、すべての状況でメソッドがファイルを返すことが常に保証されているわけではないことは明らかです。しかし、実際にQを読んだ場合、OPは、構造上、ファイルとフォルダーを処理することが100%保証されます。Qはディレクトリとファイルへのアクセスを取得するように求めています-これは、APIの一般化された抽象化よりも具体的です。ファイルへの変換は、ニーズを満たすために適切かつ適切です。そのような強く反対するコメントを投稿する前に、Qを適切に読んでください。乾杯。
グレンベスト

7
OPがファイルとディレクトリを処理していません。彼はJARファイル内のリソースを操作しています。JARファイル内のリソースはファイルまたはディレクトリではなく、Fileクラスとともにリストすることはできません。このコードは、JARファイル内のリソースでは機能しません。限目。
ローン侯爵

7

これは何年も前のことです。しかし、他の人だけがこのトピックに出くわします。あなたができることはgetResourceAsStream()ディレクトリパスでメソッドを使用することであり、入力ストリームはそのディレクトリからのすべてのファイル名を持ちます。その後、dirパスを各ファイル名と連結し、ループ内の各ファイルに対してgetResourceAsStreamを呼び出すことができます。


7
それは結局のところ、物事を妨害することを計画しない限り、これはうまく機能します。
Tustin2121

1
クリーンで、jarとIDEのバージョンを個別に処理する必要がないため、これは受け入れられるソリューションであると思います。なぜgetResourceがフォルダを見つけられないのかはわかりませんが、getResourceAsStreamは見つけます。
Raghuram Onti Srinivasan

6

IDEとjar(リリースバージョン)の両方で、jarにパックされたリソースからいくつかのhadoop構成をロードしようとしたときに、同じ問題が発生しました。

java.nio.file.DirectoryStreamローカルファイルシステムとjarの両方でディレクトリの内容を反復処理するのに最適であることがわかりました。

String fooFolder = "/foo/folder";
....

ClassLoader classLoader = foofClass.class.getClassLoader();
try {
    uri = classLoader.getResource(fooFolder).toURI();
} catch (URISyntaxException e) {
    throw new FooException(e.getMessage());
} catch (NullPointerException e){
    throw new FooException(e.getMessage());
}

if(uri == null){
    throw new FooException("something is wrong directory or files missing");
}

/** i want to know if i am inside the jar or working on the IDE*/
if(uri.getScheme().contains("jar")){
    /** jar case */
    try{
        URL jar = FooClass.class.getProtectionDomain().getCodeSource().getLocation();
        //jar.toString() begins with file:
        //i want to trim it out...
        Path jarFile = Paths.get(jar.toString().substring("file:".length()));
        FileSystem fs = FileSystems.newFileSystem(jarFile, null);
        DirectoryStream<Path> directoryStream = Files.newDirectoryStream(fs.getPath(fooFolder));
        for(Path p: directoryStream){
            InputStream is = FooClass.class.getResourceAsStream(p.toString()) ;
        performFooOverInputStream(is);
        /** your logic here **/
            }
    }catch(IOException e) {
        throw new FooException(e.getMessage());     
    }
}
else{
    /** IDE case */
    Path path = Paths.get(uri);
    try {
        DirectoryStream<Path> directoryStream = Files.newDirectoryStream(path);
        for(Path p : directoryStream){
            InputStream is = new FileInputStream(p.toFile());
            performFooOverInputStream(is);
        }
    } catch (IOException _e) {
        throw new FooException(_e.getMessage());
    }
}

これでうまくいきました。私だけが 'Path jarFile = Paths.get(jar.toString()。substring( "file:"。length()));'を切り替えました 「Path jarFile = Paths.get(jar.toURI());」Windowsで動作するようにします。FileSystemオブジェクトのリソースステートメントの試用も使用しました。
Jarle Jacobsen、

これは私のために働いた!Dockerでdropwizardアプリケーションを実行していました。
nIKUNJ

4

次のコードは、jar内にあるかどうかに関係なく、必要な「フォルダ」をパスとして返します。

  private Path getFolderPath() throws URISyntaxException, IOException {
    URI uri = getClass().getClassLoader().getResource("folder").toURI();
    if ("jar".equals(uri.getScheme())) {
      FileSystem fileSystem = FileSystems.newFileSystem(uri, Collections.emptyMap(), null);
      return fileSystem.getPath("path/to/folder/inside/jar");
    } else {
      return Paths.get(uri);
    }
  }

Java 7以降が必要です。


いいね!ただし、FileSystemはCloseableであることを追加する必要があります。つまり、システムリソースを解放するには、ある時点でFileSystemを閉じる必要があります。もちろん、返されたパスはその直後に無効になります。
Kirill Gamazkov

jarファイルの場合、ファイルシステムの作成時にリソースの名前(ここではパッケージ + folder)は無視されているように見えることに注意してください。したがって、getPath戻りませんが、戻ります。folder/path/to/...path/to/...
Marcono1234

1

別の解決策、次のResourceLoaderようにしてそれを行うことができます:

import org.springframework.core.io.Resource;
import org.apache.commons.io.FileUtils;

@Autowire
private ResourceLoader resourceLoader;

...

Resource resource = resourceLoader.getResource("classpath:/path/to/you/dir");
File file = resource.getFile();
Iterator<File> fi = FileUtils.iterateFiles(file, null, true);
while(fi.hasNext()) {
    load(fi.next())
}

0

シンプル... OSGiを使用します。OSGiでは、findEntriesとfindPathsを使用してバンドルのエントリを反復処理できます。


10
OSGIが関係している場合は、「シンプル」とは言えません。しかし、もしあなたがたまたまOSGIを使っているなら...そうです。しかし、この特定の問題を解決するためだけにOSGIに移行することを提案することは、少なすぎます。
クリス

OSGiは他の多くの問題も解決し、今日では簡単に始めることができます。OSGi enRouteのチュートリアルを参照してください
Peter Kriens

OSGiを使用する必要がない限り、私はOSGiから離れます。90年代のIMOの展開の問題を解決するオーバーデザインのブロートウェア。
user2337270 2017

-1

私のjarファイル内にはUploadというフォルダーがあり、このフォルダー内には他に3つのテキストファイルがあり、jarファイルの外にまったく同じフォルダーとファイルが必要でした。以下のコードを使用しました。

URL inputUrl = getClass().getResource("/upload/blabla1.txt");
File dest1 = new File("upload/blabla1.txt");
FileUtils.copyURLToFile(inputUrl, dest1);

URL inputUrl2 = getClass().getResource("/upload/blabla2.txt");
File dest2 = new File("upload/blabla2.txt");
FileUtils.copyURLToFile(inputUrl2, dest2);

URL inputUrl3 = getClass().getResource("/upload/blabla3.txt");
File dest3 = new File("upload/Bblabla3.txt");
FileUtils.copyURLToFile(inputUrl3, dest3);

1
こんにちは、回答に感謝しますが、コードを作成するときは、そのフォルダー内の各ファイルの名前を知る必要がありました。それぞれに明示的に名前を付ける必要がありました。私が探していたのは、フォルダー内のファイルを反復処理し、実行時にファイルの名前を取得する方法でした。そのため、コードを変更せずに、リソースもフォルダーに追加でき、コードがファイルを処理することもわかっていました。あなたの時間をありがとう。:3
モスタファZeinali 2015年

-1

他の回答が指摘するように、リソースがjarファイル内にあると、事態は非常に醜くなります。私たちの場合、このソリューションは:

https://stackoverflow.com/a/13227570/516188

テストでは非常にうまく機能しますが(テストを実行するとコードはjarファイルにパックされないため)、アプリが実際に正常に実行されると機能しません。だから私がやったことは...私はアプリでファイルのリストをハードコードしますが、私は実際のリストをディスクから読み取り(それはテストで機能するのでそれを行うことができます)、実際のリストがそうでなければ失敗しますアプリが返すリストと一致しません。

そうすれば私は私のアプリで簡単なコード(なしトリックを)持っている、私は感謝のテストに、リストに新しいエントリを追加するのを忘れていなかったと確信しています。


-25

このリンクはその方法を説明しています。

魔法はgetResourceAsStream()メソッドです:

InputStream is = 
this.getClass().getClassLoader().getResourceAsStream("yourpackage/mypackage/myfile.xml")

20
いいえおとこーおれ!!単一のファイルは必要ありません!! サブファイルが実行前に決定されていないフォルダー全体が必要です!!!
モスタファZeinali
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.