从类路径目录获取资源列表

发布于 2024-09-27 17:35:54 字数 588 浏览 4 评论 0 原文

我正在寻找一种方法来从给定的类路径目录中获取所有资源名称的列表,类似于方法 List; getResourceNames(字符串目录名称)

例如,给定一个包含文件 a.htmlb.htmlc.html< 的类路径目录 x/y/z /code> 和子目录 dgetResourceNames("x/y/z") 应返回包含以下字符串的 List :['a.html', 'b.html', 'c.html', 'd']

它应该适用于文件系统和 jar 中的资源。

我知道我可以使用 FileJarFileURL 编写快速片段,但我不想重新发明轮子。我的问题是,考虑到现有的公共可用库,实现 getResourceNames 的最快方法是什么? Spring 和 Apache Commons 堆栈都是可行的。

I am looking for a way to get a list of all resource names from a given classpath directory, something like a method List<String> getResourceNames (String directoryName).

For example, given a classpath directory x/y/z containing files a.html, b.html, c.html and a subdirectory d, getResourceNames("x/y/z") should return a List<String> containing the following strings:['a.html', 'b.html', 'c.html', 'd'].

It should work both for resources in filesystem and jars.

I know that I can write a quick snippet with Files, JarFiles and URLs, but I do not want to reinvent the wheel. My question is, given existing publicly available libraries, what is the quickest way to implement getResourceNames? Spring and Apache Commons stacks are both feasible.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(18

鯉魚旗 2024-10-04 17:35:54

自定义扫描仪

实施您自己的扫描仪。例如:(

评论中提到了该解决方案的局限性< /a>)

private List<String> getResourceFiles(String path) throws IOException {
    List<String> filenames = new ArrayList<>();

    try (
            InputStream in = getResourceAsStream(path);
            BufferedReader br = new BufferedReader(new InputStreamReader(in))) {
        String resource;

        while ((resource = br.readLine()) != null) {
            filenames.add(resource);
        }
    }

    return filenames;
}

private InputStream getResourceAsStream(String resource) {
    final InputStream in
            = getContextClassLoader().getResourceAsStream(resource);

    return in == null ? getClass().getResourceAsStream(resource) : in;
}

private ClassLoader getContextClassLoader() {
    return Thread.currentThread().getContextClassLoader();
}

Spring 框架

使用 PathMatchingResourcePatternResolver

Ronmamo 反思

对于巨大的 CLASSPATH 值,其他技术在运行时可能会很慢。更快的解决方案是使用 ronmamo 的 Reflections API,它在编译时预编译搜索。

Custom Scanner

Implement your own scanner. For example:

(limitations of this solution are mentioned in the comments)

private List<String> getResourceFiles(String path) throws IOException {
    List<String> filenames = new ArrayList<>();

    try (
            InputStream in = getResourceAsStream(path);
            BufferedReader br = new BufferedReader(new InputStreamReader(in))) {
        String resource;

        while ((resource = br.readLine()) != null) {
            filenames.add(resource);
        }
    }

    return filenames;
}

private InputStream getResourceAsStream(String resource) {
    final InputStream in
            = getContextClassLoader().getResourceAsStream(resource);

    return in == null ? getClass().getResourceAsStream(resource) : in;
}

private ClassLoader getContextClassLoader() {
    return Thread.currentThread().getContextClassLoader();
}

Spring Framework

Use PathMatchingResourcePatternResolver from Spring Framework.

Ronmamo Reflections

The other techniques might be slow at runtime for huge CLASSPATH values. A faster solution is to use ronmamo's Reflections API, which precompiles the search at compile time.

呢古 2024-10-04 17:35:54

这是代码
来源:forums.devx.com/showthread.php?t=153784

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;

/**
 * list resources available from the classpath @ *
 */
public class ResourceList{

    /**
     * for all elements of java.class.path get a Collection of resources Pattern
     * pattern = Pattern.compile(".*"); gets all resources
     * 
     * @param pattern
     *            the pattern to match
     * @return the resources in the order they are found
     */
    public static Collection<String> getResources(
        final Pattern pattern){
        final ArrayList<String> retval = new ArrayList<String>();
        final String classPath = System.getProperty("java.class.path", ".");
        final String[] classPathElements = classPath.split(System.getProperty("path.separator"));
        for(final String element : classPathElements){
            retval.addAll(getResources(element, pattern));
        }
        return retval;
    }

    private static Collection<String> getResources(
        final String element,
        final Pattern pattern){
        final ArrayList<String> retval = new ArrayList<String>();
        final File file = new File(element);
        if(file.isDirectory()){
            retval.addAll(getResourcesFromDirectory(file, pattern));
        } else{
            retval.addAll(getResourcesFromJarFile(file, pattern));
        }
        return retval;
    }

    private static Collection<String> getResourcesFromJarFile(
        final File file,
        final Pattern pattern){
        final ArrayList<String> retval = new ArrayList<String>();
        ZipFile zf;
        try{
            zf = new ZipFile(file);
        } catch(final ZipException e){
            throw new Error(e);
        } catch(final IOException e){
            throw new Error(e);
        }
        final Enumeration e = zf.entries();
        while(e.hasMoreElements()){
            final ZipEntry ze = (ZipEntry) e.nextElement();
            final String fileName = ze.getName();
            final boolean accept = pattern.matcher(fileName).matches();
            if(accept){
                retval.add(fileName);
            }
        }
        try{
            zf.close();
        } catch(final IOException e1){
            throw new Error(e1);
        }
        return retval;
    }

    private static Collection<String> getResourcesFromDirectory(
        final File directory,
        final Pattern pattern){
        final ArrayList<String> retval = new ArrayList<String>();
        final File[] fileList = directory.listFiles();
        for(final File file : fileList){
            if(file.isDirectory()){
                retval.addAll(getResourcesFromDirectory(file, pattern));
            } else{
                try{
                    final String fileName = file.getCanonicalPath();
                    final boolean accept = pattern.matcher(fileName).matches();
                    if(accept){
                        retval.add(fileName);
                    }
                } catch(final IOException e){
                    throw new Error(e);
                }
            }
        }
        return retval;
    }

    /**
     * list the resources that match args[0]
     * 
     * @param args
     *            args[0] is the pattern to match, or list all resources if
     *            there are no args
     */
    public static void main(final String[] args){
        Pattern pattern;
        if(args.length < 1){
            pattern = Pattern.compile(".*");
        } else{
            pattern = Pattern.compile(args[0]);
        }
        final Collection<String> list = ResourceList.getResources(pattern);
        for(final String name : list){
            System.out.println(name);
        }
    }
}  

如果您使用 Spring 请查看 PathMatchingResourcePatternResolver

Here is the code
Source: forums.devx.com/showthread.php?t=153784

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;

/**
 * list resources available from the classpath @ *
 */
public class ResourceList{

    /**
     * for all elements of java.class.path get a Collection of resources Pattern
     * pattern = Pattern.compile(".*"); gets all resources
     * 
     * @param pattern
     *            the pattern to match
     * @return the resources in the order they are found
     */
    public static Collection<String> getResources(
        final Pattern pattern){
        final ArrayList<String> retval = new ArrayList<String>();
        final String classPath = System.getProperty("java.class.path", ".");
        final String[] classPathElements = classPath.split(System.getProperty("path.separator"));
        for(final String element : classPathElements){
            retval.addAll(getResources(element, pattern));
        }
        return retval;
    }

    private static Collection<String> getResources(
        final String element,
        final Pattern pattern){
        final ArrayList<String> retval = new ArrayList<String>();
        final File file = new File(element);
        if(file.isDirectory()){
            retval.addAll(getResourcesFromDirectory(file, pattern));
        } else{
            retval.addAll(getResourcesFromJarFile(file, pattern));
        }
        return retval;
    }

    private static Collection<String> getResourcesFromJarFile(
        final File file,
        final Pattern pattern){
        final ArrayList<String> retval = new ArrayList<String>();
        ZipFile zf;
        try{
            zf = new ZipFile(file);
        } catch(final ZipException e){
            throw new Error(e);
        } catch(final IOException e){
            throw new Error(e);
        }
        final Enumeration e = zf.entries();
        while(e.hasMoreElements()){
            final ZipEntry ze = (ZipEntry) e.nextElement();
            final String fileName = ze.getName();
            final boolean accept = pattern.matcher(fileName).matches();
            if(accept){
                retval.add(fileName);
            }
        }
        try{
            zf.close();
        } catch(final IOException e1){
            throw new Error(e1);
        }
        return retval;
    }

    private static Collection<String> getResourcesFromDirectory(
        final File directory,
        final Pattern pattern){
        final ArrayList<String> retval = new ArrayList<String>();
        final File[] fileList = directory.listFiles();
        for(final File file : fileList){
            if(file.isDirectory()){
                retval.addAll(getResourcesFromDirectory(file, pattern));
            } else{
                try{
                    final String fileName = file.getCanonicalPath();
                    final boolean accept = pattern.matcher(fileName).matches();
                    if(accept){
                        retval.add(fileName);
                    }
                } catch(final IOException e){
                    throw new Error(e);
                }
            }
        }
        return retval;
    }

    /**
     * list the resources that match args[0]
     * 
     * @param args
     *            args[0] is the pattern to match, or list all resources if
     *            there are no args
     */
    public static void main(final String[] args){
        Pattern pattern;
        if(args.length < 1){
            pattern = Pattern.compile(".*");
        } else{
            pattern = Pattern.compile(args[0]);
        }
        final Collection<String> list = ResourceList.getResources(pattern);
        for(final String name : list){
            System.out.println(name);
        }
    }
}  

If you are using Spring Have a look at PathMatchingResourcePatternResolver

谜兔 2024-10-04 17:35:54

使用反射

当提出这个问题时,这个答案是有效的。随后,我认为 Reflections 项目的维护并没有太一致。我将答案留在这里,但我现在会亲自查看其他一些答案,例如使用 classgraph< 的答案/a>.


原始答案:

使用 Reflections

获取类路径上的所有内容:

Reflections reflections = new Reflections(null, new ResourcesScanner());
Set<String> resourceList = reflections.getResources(x -> true);

另一个示例 - 从 some.package 获取扩展名为 .csv 的所有文件:

Reflections reflections = new Reflections("some.package", new ResourcesScanner());
Set<String> resourceList = reflections.getResources(Pattern.compile(".*\\.csv"));

请注意:(更新)

这个答案写于 2015 年,可能使用了 Reflections 0.9.10。随后,我尝试了更高版本的 Reflections 库,并努力让这个答案发挥作用。我还努力从他们自己的文档中获取示例来工作...就我个人而言,我不确定该项目的维护者在做什么...也许这是我的一个错误。

Reflections 项目已从 Google Code Archive 版本 0.9.9-RC1,显而易见 [此处]。该项目目前在 github [此处] 上进行维护。

Using Reflections.

This answer was valid when this questions was asked. Subsequently I don't think the Reflections project has been maintained too consistently. I am leaving the answer here, but I would personally look at some of the other answers now for example the ones using classgraph.


Original answer:

Using Reflections.

Get everything on the classpath:

Reflections reflections = new Reflections(null, new ResourcesScanner());
Set<String> resourceList = reflections.getResources(x -> true);

Another example - get all files with extension .csv from some.package:

Reflections reflections = new Reflections("some.package", new ResourcesScanner());
Set<String> resourceList = reflections.getResources(Pattern.compile(".*\\.csv"));

Please note: (update)

This answer was written in 2015 and probably used Reflections 0.9.10. Subsequently I've tried the later versions of the Reflections library and struggled getting this answer to work. I also struggled to get examples from their own documentation to work... Personally I'm not sure what the maintainers of the project is doing... Maybe it's an error on my part.

The Reflections project was migrated from the Google Code Archive at version 0.9.9-RC1 as is evident [here]. The project is currently being maintained on github [here].

生生漫 2024-10-04 17:35:54

因此,就 PathMatchingResourcePatternResolver 而言,这就是代码中所需要的:

@Autowired
ResourcePatternResolver resourceResolver;

public void getResources() {
  resourceResolver.getResources("classpath:config/*.xml");
}

So in terms of the PathMatchingResourcePatternResolver this is what is needed in the code:

@Autowired
ResourcePatternResolver resourceResolver;

public void getResources() {
  resourceResolver.getResources("classpath:config/*.xml");
}
拥醉 2024-10-04 17:35:54

目前列出类路径中所有资源的最强大的机制是 将此模式与 ClassGraph 结合使用,因为它可以处理最广泛的可能一系列类路径规范机制,包括新的 JPMS 模块系统。 (我是 ClassGraph 的作者。)

List<String> resourceNames;
try (ScanResult scanResult = new ClassGraph().acceptPaths("x/y/z").scan()) {
    resourceNames = scanResult.getAllResources().getNames();
}

The most robust mechanism for listing all resources in the classpath is currently to use this pattern with ClassGraph, because it handles the widest possible array of classpath specification mechanisms, including the new JPMS module system. (I am the author of ClassGraph.)

List<String> resourceNames;
try (ScanResult scanResult = new ClassGraph().acceptPaths("x/y/z").scan()) {
    resourceNames = scanResult.getAllResources().getNames();
}
疯了 2024-10-04 17:35:54

如果您使用 apache commonsIO,您可以用于文件系统(可选地使用扩展过滤器):

Collection<File> files = FileUtils.listFiles(new File("directory/"), null, false);

以及资源/类路径:

List<String> files = IOUtils.readLines(MyClass.class.getClassLoader().getResourceAsStream("directory/"), Charsets.UTF_8);

如果您不知道“directoy/”是否在文件系统中或在资源中,您可以

if (new File("directory/").isDirectory())

添加或

if (MyClass.class.getClassLoader().getResource("directory/") != null)

在调用之前 并结合使用两者......

If you use apache commonsIO you can use for the filesystem (optionally with extension filter):

Collection<File> files = FileUtils.listFiles(new File("directory/"), null, false);

and for resources/classpath:

List<String> files = IOUtils.readLines(MyClass.class.getClassLoader().getResourceAsStream("directory/"), Charsets.UTF_8);

If you don't know if "directoy/" is in the filesystem or in resources you may add a

if (new File("directory/").isDirectory())

or

if (MyClass.class.getClassLoader().getResource("directory/") != null)

before the calls and use both in combination...

旧时模样 2024-10-04 17:35:54

Spring 框架PathMatchingResourcePatternResolver 在以下方面确实很棒:

private Resource[] getXMLResources() throws IOException
{
    ClassLoader classLoader = MethodHandles.lookup().getClass().getClassLoader();
    PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(classLoader);

    return resolver.getResources("classpath:x/y/z/*.xml");
}

Maven 依赖项:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>LATEST</version>
</dependency>

The Spring framework's PathMatchingResourcePatternResolver is really awesome for these things:

private Resource[] getXMLResources() throws IOException
{
    ClassLoader classLoader = MethodHandles.lookup().getClass().getClassLoader();
    PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(classLoader);

    return resolver.getResources("classpath:x/y/z/*.xml");
}

Maven dependency:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>LATEST</version>
</dependency>
水染的天色ゝ 2024-10-04 17:35:54

这应该可行(如果弹簧不是一个选项):

public static List<String> getFilenamesForDirnameFromCP(String directoryName) throws URISyntaxException, UnsupportedEncodingException, IOException {
    List<String> filenames = new ArrayList<>();

    URL url = Thread.currentThread().getContextClassLoader().getResource(directoryName);
    if (url != null) {
        if (url.getProtocol().equals("file")) {
            File file = Paths.get(url.toURI()).toFile();
            if (file != null) {
                File[] files = file.listFiles();
                if (files != null) {
                    for (File filename : files) {
                        filenames.add(filename.toString());
                    }
                }
            }
        } else if (url.getProtocol().equals("jar")) {
            String dirname = directoryName + "/";
            String path = url.getPath();
            String jarPath = path.substring(5, path.indexOf("!"));
            try (JarFile jar = new JarFile(URLDecoder.decode(jarPath, StandardCharsets.UTF_8.name()))) {
                Enumeration<JarEntry> entries = jar.entries();
                while (entries.hasMoreElements()) {
                    JarEntry entry = entries.nextElement();
                    String name = entry.getName();
                    if (name.startsWith(dirname) && !dirname.equals(name)) {
                        URL resource = Thread.currentThread().getContextClassLoader().getResource(name);
                        filenames.add(resource.toString());
                    }
                }
            }
        }
    }
    return filenames;
}

This should work (if spring is not an option):

public static List<String> getFilenamesForDirnameFromCP(String directoryName) throws URISyntaxException, UnsupportedEncodingException, IOException {
    List<String> filenames = new ArrayList<>();

    URL url = Thread.currentThread().getContextClassLoader().getResource(directoryName);
    if (url != null) {
        if (url.getProtocol().equals("file")) {
            File file = Paths.get(url.toURI()).toFile();
            if (file != null) {
                File[] files = file.listFiles();
                if (files != null) {
                    for (File filename : files) {
                        filenames.add(filename.toString());
                    }
                }
            }
        } else if (url.getProtocol().equals("jar")) {
            String dirname = directoryName + "/";
            String path = url.getPath();
            String jarPath = path.substring(5, path.indexOf("!"));
            try (JarFile jar = new JarFile(URLDecoder.decode(jarPath, StandardCharsets.UTF_8.name()))) {
                Enumeration<JarEntry> entries = jar.entries();
                while (entries.hasMoreElements()) {
                    JarEntry entry = entries.nextElement();
                    String name = entry.getName();
                    if (name.startsWith(dirname) && !dirname.equals(name)) {
                        URL resource = Thread.currentThread().getContextClassLoader().getResource(name);
                        filenames.add(resource.toString());
                    }
                }
            }
        }
    }
    return filenames;
}
皇甫轩 2024-10-04 17:35:54

我的方式,没有 Spring,在单元测试期间使用:

URI uri = TestClass.class.getResource("/resources").toURI();
Path myPath = Paths.get(uri);
Stream<Path> walk = Files.walk(myPath, 1);
for (Iterator<Path> it = walk.iterator(); it.hasNext(); ) {
    Path filename = it.next();   
    System.out.println(filename);
}

My way, no Spring, used during a unit test:

URI uri = TestClass.class.getResource("/resources").toURI();
Path myPath = Paths.get(uri);
Stream<Path> walk = Files.walk(myPath, 1);
for (Iterator<Path> it = walk.iterator(); it.hasNext(); ) {
    Path filename = it.next();   
    System.out.println(filename);
}
夏末 2024-10-04 17:35:54

有了Spring,这很容易。无论是文件、文件夹,甚至多个文件,都有机会通过注入来完成。

此示例演示了位于 x/y/z 文件夹中的多个文件的注入。

import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;

@Service
public class StackoverflowService {
    @Value("classpath:x/y/z/*")
    private Resource[] resources;

    public List<String> getResourceNames() {
        return Arrays.stream(resources)
                .map(Resource::getFilename)
                .collect(Collectors.toList());
    }
}

它确实适用于文件系统和 JAR 中的资源。

With Spring it's easy. Be it a file, or folder, or even multiple files, there are chances, you can do it via injection.

This example demonstrates the injection of multiple files located in x/y/z folder.

import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;

@Service
public class StackoverflowService {
    @Value("classpath:x/y/z/*")
    private Resource[] resources;

    public List<String> getResourceNames() {
        return Arrays.stream(resources)
                .map(Resource::getFilename)
                .collect(Collectors.toList());
    }
}

It does work for resources in the filesystem as well as in JARs.

等风来 2024-10-04 17:35:54

path-matching-resource-pattern-resolver

我将 Spring Framework 的 PathMatchingResourcePatternResolver 提取到一个独立的库中,供那些不能或不想导入整个 Spring Framework 库的人使用。

GitHub

https://github.com/SecretX33/path-matching-resource-pattern -resolver

添加依赖

Maven

<dependency>
    <groupId>io.github.secretx33</groupId>
    <artifactId>path-matching-resource-pattern-resolver</artifactId>
    <version>0.1</version>
</dependency>

Gradle

implementation 'io.github.secretx33:path-matching-resource-pattern-resolver:0.1'

Gradle (KTS)

implementation("io.github.secretx33:path-matching-resource-pattern-resolver:0.1")

使用示例

查找单个资源

ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource resource = resolver.getResource("classpath:com/example/config.properties");

if (resource.exists()) {
    // Process the resource
}

查找多个资源

ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource[] resources = resolver.getResources("classpath:com/example/**/*.xml");

for (Resource resource : resources) {
    // Process the resource
}

path-matching-resource-pattern-resolver

I extracted Spring Framework's PathMatchingResourcePatternResolver into a standalone library for those that can't or don't want to import the whole Spring Framework library.

GitHub

https://github.com/SecretX33/path-matching-resource-pattern-resolver

Add the dependency

Maven

<dependency>
    <groupId>io.github.secretx33</groupId>
    <artifactId>path-matching-resource-pattern-resolver</artifactId>
    <version>0.1</version>
</dependency>

Gradle

implementation 'io.github.secretx33:path-matching-resource-pattern-resolver:0.1'

Gradle (KTS)

implementation("io.github.secretx33:path-matching-resource-pattern-resolver:0.1")

Usage example

Find a single resource

ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource resource = resolver.getResource("classpath:com/example/config.properties");

if (resource.exists()) {
    // Process the resource
}

Find multiple resources

ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource[] resources = resolver.getResources("classpath:com/example/**/*.xml");

for (Resource resource : resources) {
    // Process the resource
}
挽心 2024-10-04 17:35:54

我认为您可以利用 [Zip 文件系统提供程序][1] 来实现此目的。使用 FileSystems.newFileSystem 时,您似乎可以将该 ZIP 中的对象视为“常规”文件。

在上面的链接文档中:

在传递给 FileSystems.newFileSystem 方法的 java.util.Map 对象中指定 zip 文件系统的配置选项。有关 zip 文件系统的特定于提供程序的配置属性的信息,请参阅 [Zip 文件系统属性][2] 主题。

一旦有了 zip 文件系统的实例,您就可以调用 [java.nio.file.FileSystem][3] 和 [java.nio.file .Path][4]类用于执行复制、移动和重命名文件以及修改文件属性等操作。

[Java 11 states][5] 中 jdk.zipfs 模块的文档:

zip 文件系统提供程序将 zip 或 JAR 文件视为文件系统,并提供操作文件内容的能力。如果已安装,则可以通过 [FileSystems.newFileSystem][6] 创建 zip 文件系统提供程序。

这是我使用您的示例资源制作的一个示例。请注意,.zip.jar,但您可以调整代码以使用类路径资源:

Setup

cd /tmp
mkdir -p x/y/z
touch x/y/z/{a,b,c}.html
echo 'hello world' > x/y/z/d
zip -r example.zip x

Java

import java.io.IOException;
import java.net.URI;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.util.Collections;
import java.util.stream.Collectors;

public class MkobitZipRead {

  public static void main(String[] args) throws IOException {
    final URI uri = URI.create("jar:file:/tmp/example.zip");
    try (
        final FileSystem zipfs = FileSystems.newFileSystem(uri, Collections.emptyMap());
    ) {
      Files.walk(zipfs.getPath("/")).forEach(path -> System.out.println("Files in zip:" + path));
      System.out.println("-----");
      final String manifest = Files.readAllLines(
          zipfs.getPath("x", "y", "z").resolve("d")
      ).stream().collect(Collectors.joining(System.lineSeparator()));
      System.out.println(manifest);
    }
  }

}

输出

Files in zip:/
Files in zip:/x/
Files in zip:/x/y/
Files in zip:/x/y/z/
Files in zip:/x/y/z/c.html
Files in zip:/x/y/z/b.html
Files in zip:/x/y/z/a.html
Files in zip:/x/y/z/d
-----
hello world

I think you can leverage the [Zip File System Provider][1] to achieve this. When using FileSystems.newFileSystem it looks like you can treat the objects in that ZIP as a "regular" file.

In the linked documentation above:

Specify the configuration options for the zip file system in the java.util.Map object passed to the FileSystems.newFileSystem method. See the [Zip File System Properties][2] topic for information about the provider-specific configuration properties for the zip file system.

Once you have an instance of a zip file system, you can invoke the methods of the [java.nio.file.FileSystem][3] and [java.nio.file.Path][4] classes to perform operations such as copying, moving, and renaming files, as well as modifying file attributes.

The documentation for the jdk.zipfs module in [Java 11 states][5]:

The zip file system provider treats a zip or JAR file as a file system and provides the ability to manipulate the contents of the file. The zip file system provider can be created by [FileSystems.newFileSystem][6] if installed.

Here is a contrived example I did using your example resources. Note that a .zip is a .jar, but you could adapt your code to instead use classpath resources:

Setup

cd /tmp
mkdir -p x/y/z
touch x/y/z/{a,b,c}.html
echo 'hello world' > x/y/z/d
zip -r example.zip x

Java

import java.io.IOException;
import java.net.URI;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.util.Collections;
import java.util.stream.Collectors;

public class MkobitZipRead {

  public static void main(String[] args) throws IOException {
    final URI uri = URI.create("jar:file:/tmp/example.zip");
    try (
        final FileSystem zipfs = FileSystems.newFileSystem(uri, Collections.emptyMap());
    ) {
      Files.walk(zipfs.getPath("/")).forEach(path -> System.out.println("Files in zip:" + path));
      System.out.println("-----");
      final String manifest = Files.readAllLines(
          zipfs.getPath("x", "y", "z").resolve("d")
      ).stream().collect(Collectors.joining(System.lineSeparator()));
      System.out.println(manifest);
    }
  }

}

Output

Files in zip:/
Files in zip:/x/
Files in zip:/x/y/
Files in zip:/x/y/z/
Files in zip:/x/y/z/c.html
Files in zip:/x/y/z/b.html
Files in zip:/x/y/z/a.html
Files in zip:/x/y/z/d
-----
hello world
风向决定发型 2024-10-04 17:35:54

结合了 Rob 的响应。

final String resourceDir = "resourceDirectory/";
List<String> files = IOUtils.readLines(Thread.currentThread().getClass().getClassLoader().getResourceAsStream(resourceDir), Charsets.UTF_8);

for (String f : files) {
  String data = IOUtils.toString(Thread.currentThread().getClass().getClassLoader().getResourceAsStream(resourceDir + f));
  // ... process data
}

Used a combination of Rob's response.

final String resourceDir = "resourceDirectory/";
List<String> files = IOUtils.readLines(Thread.currentThread().getClass().getClassLoader().getResourceAsStream(resourceDir), Charsets.UTF_8);

for (String f : files) {
  String data = IOUtils.toString(Thread.currentThread().getClass().getClassLoader().getResourceAsStream(resourceDir + f));
  // ... process data
}
忘羡 2024-10-04 17:35:54

对于根目录:

List<String> fileNames = IOUtils.readLines(MyClass.class.getClassLoader().getResourceAsStream("."), StandardCharsets.UTF_8);

For root directory:

List<String> fileNames = IOUtils.readLines(MyClass.class.getClassLoader().getResourceAsStream("."), StandardCharsets.UTF_8);
温柔一刀 2024-10-04 17:35:54
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;

@Component
public class FilesService {
    @Value("classpath:files/*.txt")
    private Resource[] files;

    @Value("classpath:files/specificFile.txt")
    private Resource file;

    //code to work with files
}

如您所见,这非常简单。当你的 jar 在服务器上运行时,它可以在运行时运行。

import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;

@Component
public class FilesService {
    @Value("classpath:files/*.txt")
    private Resource[] files;

    @Value("classpath:files/specificFile.txt")
    private Resource file;

    //code to work with files
}

As you see it's very simple. And it works in runtime, when your jar was run on the server.

静赏你的温柔 2024-10-04 17:35:54

尽管我将资源放入资源文件夹并遵循上述答案,但这两个答案都不适合我。真正的伎俩是:

@Value("file:*/**/resources/**/schema/*.json")
private Resource[] resources;

Neither of answers worked for me even though I had my resources put in resources folders and followed the above answers. What did make a trick was:

@Value("file:*/**/resources/**/schema/*.json")
private Resource[] resources;
心病无药医 2024-10-04 17:35:54

使用他的 Luke Hutchinsons 答案rel="nofollow noreferrer">ClassGraph 库,我几乎不费吹灰之力就能轻松获取资源文件夹中所有文件的列表。

假设在您的资源文件夹中,有一个名为 MyImages 的文件夹。获取该文件夹中所有文件的 URL 列表是多么容易:

import io.github.classgraph.ClassGraph;
import io.github.classgraph.ResourceList;
import io.github.classgraph.ScanResult;

public static LinkedList<URL> getURLList (String folder) {
    LinkedList<URL> urlList    = new LinkedList<>();
    ScanResult      scanResult = new ClassGraph().enableAllInfo().scan();
    ResourceList    resources  = scanResult.getAllResources();
    for (URL url : resources.getURLs()) {
        if (url.toString().contains(folder)) {
            urlList.addLast(url);
        }
    }
    return urlList;
}

然后您只需执行以下操作:

LinkedList<URL> myURLFileList = getURLList("MyImages");

然后可以将 URL 加载到流中或使用 Apache 的 FileUtils 将文件复制到其他位置,如下所示:

String outPath = "/My/Output/Path";
for(URL url : myURLFileList) {
    FileUtils.copyURLToFile(url, new File(outPath, url.getFile()));
}

我认为 ClassGraph 是一个非常漂亮的库,可以使这样的任务变得非常简单且易于理解。

Expanding on Luke Hutchinsons answer above, using his ClassGraph library, I was able to easily get a list of all files in a Resource folder with almost no effort at all.

Let's say that in your resource folder, you have a folder called MyImages. This is how easy it is to get a URL list of all the files in that folder:

import io.github.classgraph.ClassGraph;
import io.github.classgraph.ResourceList;
import io.github.classgraph.ScanResult;

public static LinkedList<URL> getURLList (String folder) {
    LinkedList<URL> urlList    = new LinkedList<>();
    ScanResult      scanResult = new ClassGraph().enableAllInfo().scan();
    ResourceList    resources  = scanResult.getAllResources();
    for (URL url : resources.getURLs()) {
        if (url.toString().contains(folder)) {
            urlList.addLast(url);
        }
    }
    return urlList;
}

Then you simply do this:

LinkedList<URL> myURLFileList = getURLList("MyImages");

The URLs can then be loaded into streams or use Apache's FileUtils to copy the files somewhere else like this:

String outPath = "/My/Output/Path";
for(URL url : myURLFileList) {
    FileUtils.copyURLToFile(url, new File(outPath, url.getFile()));
}

I think ClassGraph is a pretty slick library for making tasks like this very simple and easy to comprehend.

穿透光 2024-10-04 17:35:54

根据上面 @rob 的信息,我创建了要发布到公共领域的实现:

private static List<String> getClasspathEntriesByPath(String path) throws IOException {
    InputStream is = Main.class.getClassLoader().getResourceAsStream(path);

    StringBuilder sb = new StringBuilder();
    while (is.available()>0) {
        byte[] buffer = new byte[1024];
        sb.append(new String(buffer, Charset.defaultCharset()));
    }

    return Arrays
            .asList(sb.toString().split("\n"))          // Convert StringBuilder to individual lines
            .stream()                                   // Stream the list
            .filter(line -> line.trim().length()>0)     // Filter out empty lines
            .collect(Collectors.toList());              // Collect remaining lines into a List again
}

虽然我不希望 getResourcesAsStream 在目录上像这样工作,但它确实如此并且有效出色地。

Based on @rob 's information above, I created the implementation which I am releasing to the public domain:

private static List<String> getClasspathEntriesByPath(String path) throws IOException {
    InputStream is = Main.class.getClassLoader().getResourceAsStream(path);

    StringBuilder sb = new StringBuilder();
    while (is.available()>0) {
        byte[] buffer = new byte[1024];
        sb.append(new String(buffer, Charset.defaultCharset()));
    }

    return Arrays
            .asList(sb.toString().split("\n"))          // Convert StringBuilder to individual lines
            .stream()                                   // Stream the list
            .filter(line -> line.trim().length()>0)     // Filter out empty lines
            .collect(Collectors.toList());              // Collect remaining lines into a List again
}

While I would not have expected getResourcesAsStream to work like that on a directory, it really does and it works well.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文