web-dev-qa-db-ja.com

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

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

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

114
Mostafa Zeinali

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

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ファイルではない)でアプリケーションを実行するときに機能します。それが気に入らない場合は削除できます。

104
user1079877

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

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/");
15
Glen Best

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

7
Cheng Lin

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());
    }
}
5
SQL.injection

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

  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+が必要です。

3
hummingV

別の解決策として、次のように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())
}
1
Qy Zuo

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

0
Peter Kriens