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

via*_*tic 231 java resources classpath

我正在寻找一种方法来获取给定类路径目录中的所有资源名称列表,类似于方法List<String> getResourceNames (String directoryName).

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

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

我知道我可以用Files,JarFiles和URLs 写一个快速片段,但我不想重新发明轮子.我的问题是,鉴于现有的公共图书馆,实施最快捷的方式是getResourceNames什么?Spring和Apache Commons堆栈都是可行的.

iir*_*ekm 157

自定义扫描仪

实现自己的扫描仪.例如:

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();
}
Run Code Online (Sandbox Code Playgroud)

Spring框架

使用PathMatchingResourcePatternResolverSpring Framework.

Ronmamo思考

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

  • 从jar文件执行时,第一个解决方案是否有效?对我来说 - 事实并非如此.我可以通过这种方式读取文件,但无法读取目录. (22认同)
  • 如果使用Reflections,你真正需要的是:`new Reflections("my.package",new ResourcesScanner()).getResources(pattern)` (12认同)
  • 你无法读取这样的目录,因为没有目录而是文件流.这个答案是错误的. (5认同)
  • 本回答中描述的第一个方法 - 将路径作为资源读取,当资源与可执行代码在同一个JAR中时似乎不起作用,至少使用OpenJDK 1.8.失败是相当奇怪的 - 从JVM的文件处理逻辑深处抛出NullPointerException.就好像设计师并没有真正预料到这种资源的使用,而且只有部分实现.即使它适用于某些JDK或环境,这似乎也不是记录在案的行为. (4认同)
  • 就我而言,我想在路径中列出非类文件资源,但只显示类文件。所以我不得不将它们移动到一个不同的目录,该目录在相应的包中没有任何类。 (3认同)
  • 考虑到这基本上不适用于任何实际用例,它的响应排名有多高有点令人困惑。 (3认同)
  • 第一种方法似乎不起作用-至少在从开发环境运行时,在破坏资源之前。调用带有目录相对路径的getResourceAsStream()会导致FileInputStream(File),该文件定义为如果文件是目录则抛出FileNotFoundException。 (2认同)
  • 如果您关心在各种类路径环境以及新的 JPMS 模块路径中工作的代码,您确实不想编写自己的扫描器。不同的类路径规范机制的数量令人眼花缭乱:https://github.com/classgraph/classgraph/wiki/Classpath-Specification-Mechanisms 相反,请考虑使用 ClassGraph,它会为您处理所有这一切。(我是作者。) (2认同)

Jig*_*shi 48

这是代码
来源: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);
        }
    }
}  
Run Code Online (Sandbox Code Playgroud)

如果您使用的是Spring,请查看PathMatchingResourcePatternResolver

  • 我发现这个解决方案对于你不使用Spring的情况很有用 - 仅仅添加对Spring的依赖是荒谬的.所以谢谢!"脏"但有用:) PS One可能想在``getResources``方法中使用``File.pathSeparator``而不是硬编码``:``. (7认同)
  • 代码示例是依赖于系统的,请使用它:`final String [] classPathElements = classPath.split(System.pathSeparator);` (5认同)
  • 提问者知道如何使用标准java类实现它,但他想知道如何利用现有的(Spring,Apache Commons)库. (3认同)
  • `PathMatchingResourcePatternResolver`做了这个伎俩. (2认同)

NS *_*oit 19

使用Google思考:

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

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

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

Reflections reflections = new Reflections("some.package", new ResourcesScanner());
Set<String> fileNames = reflections.getResources(Pattern.compile(".*\\.csv"));
Run Code Online (Sandbox Code Playgroud)

  • Reflections 不是 Google 库。 (3认同)

Rob*_*Rob 16

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

Collection<File> files = FileUtils.listFiles(new File("directory/"), null, false);
Run Code Online (Sandbox Code Playgroud)

和资源/类路径:

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

如果你不知道文件系统或资源中是否有"directoy /",你可以添加一个

if (new File("directory/").isDirectory())
Run Code Online (Sandbox Code Playgroud)

要么

if (MyClass.class.getClassLoader().getResource("directory/") != null)
Run Code Online (Sandbox Code Playgroud)

在通话之前和两者结合使用......

  • 文件!=资源 (21认同)
  • 不工作(空指针异常)时的目标资源是驻留在JAR文件中的目录(即JAR包含主应用程序和目标目录) (9认同)
  • 当然,资源可能并不总是文件,但问题是关于源自文件/目录的资源.因此,如果要检查不同的位置,请使用示例代码,例如,如果资源中有一个config.xml用于某些默认配置,则应该可以加载外部config.xml(如果存在)... (3认同)
  • 为什么资源不是文件?资源是归档到zip存档中的文件.它们被加载到内存中并以特定方式访问,但我不明白为什么它们不是文件.任何资源都不是"存档中的文件"吗? (2认同)

小智 11

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

@Autowired
ResourcePatternResolver resourceResolver;

public void getResources() {
  resourceResolver.getResources("classpath:config/*.xml");
}
Run Code Online (Sandbox Code Playgroud)

  • 如果你想在你需要使用的所有类路径中搜索所有可能的资源,只是一个小补充,使用 `classpath*:config/*.xml` (2认同)

Luk*_*son 6

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

List<String> resourceNames;
try (ScanResult scanResult = new ClassGraph().whitelistPaths("x/y/z").scan()) {
    resourceNames = scanResult.getAllResources().getNames();
}
Run Code Online (Sandbox Code Playgroud)

  • 哈奇森先生干得好!也许这是我在 Java 世界中发现的可用资源的最简单、最直接的方法。感谢您提供了一个很棒的图书馆! (4认同)
  • 具有一致行为的优秀库。 (2认同)

Tre*_*vor 5

使用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
}
Run Code Online (Sandbox Code Playgroud)

  • 如何获取*所有*资源:即以“/”或“.”或“./”开头,但实际上都不起作用 (2认同)

Bul*_*aza 5

Spring frameworkPathMatchingResourcePatternResolver是这些东西真的真棒:

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

    return resolver.getResources("classpath:x/y/z/*.xml");
}
Run Code Online (Sandbox Code Playgroud)

Maven依赖:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>LATEST</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)


fl0*_*l0w 5

这应该有效(如果不能选择 spring):

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;
}
Run Code Online (Sandbox Code Playgroud)


Jac*_*rts 5

我的方式,没有 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);
}
Run Code Online (Sandbox Code Playgroud)

  • 不起作用,当您运行 jar 时: java.nio.file.FileSystemNotFoundException at Paths.get(uri) (6认同)