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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3923129/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 06:57:13  来源:igfitidea点击:

Get a list of resources from classpath directory

javaresourcesclasspath

提问by viaclectic

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).

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

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

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

It should work both for resources in filesystem and jars.

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

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.

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

采纳答案by iirekm

Custom Scanner

自定义扫描仪

Implement your own scanner. For example:

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

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 PathMatchingResourcePatternResolverfrom Spring Framework.

PathMatchingResourcePatternResolver从 Spring 框架使用。

Ronmamo Reflections

Romamo 思考

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.

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

回答by Jigar Joshi

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

这是代码
来源: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

如果您使用的是 Spring 看看PathMatchingResourcePatternResolver

回答by Rob

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

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

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

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

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

or

或者

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

before the calls and use both in combination...

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

回答by Pavel Kotlov

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

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

@Autowired
ResourcePatternResolver resourceResolver;

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

回答by Trevor

Used a combination of Rob's response.

结合使用了 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
}

回答by NS du Toit

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 .csvfrom some.package:

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

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

回答by Deven Phillips

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

基于@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
}

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

虽然我没想到会getResourcesAsStream在目录上这样工作,但确实如此,而且效果很好。

回答by BullyWiiPlaza

The Spring framework's PathMatchingResourcePatternResolveris really awesome for these things:

对于这些事情,Spring framework'sPathMatchingResourcePatternResolver真的很棒:

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:

Maven 依赖:

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

回答by fl0w

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

这应该有效(如果不能选择 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;
}

回答by naXa

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

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

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

此示例演示了位于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());
    }
}

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

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