当前位置: 首页 > 知识库问答 >
问题:

java-如何在jar中列出资源中的目录

盛浩阔
2023-03-14

让我们有一个maven项目,其资源结构如下:

src/主/资源

  • 目录1
    • 细分1
      • 文件
      • 文件

      虽然我找到了许多关于如何列出文件资源的答案,但我一直在寻找一种方法,如何列出资源中目录(或路径)的所有直接子目录,当应用程序同时从IDE(IntelliJ)和jar运行时,这种方法就行得通了。

      目标是获取目录“di1”的子目录名称:subdi1, subdi2

      我试过了

      Thread.currentThread().getContextClassLoader().getResourceAsStream("dir1");
      

      和使用返回的InputStream(包含子目录的名称),但不适用于jar。IntelliJ的作品。

      我也试过用Spring框架但是

      PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
      Resource[] resources = resolver.getResources("dir1/*");
      

      无法在jar中正常工作-资源数组为空。从IntelliJ工作。

      我试图修改为

      Resource[] resources = resolver.getResources("dir1/*/");
      

      它可以从jar工作,但不能从IntelliJ工作。

      当我从罐子开始工作时,我会以另一种方式打破它,反之亦然。我的最后一个想法是

      Resource[] resources = resolver.getResources("dir1/**");
      

      获取目录下的所有资源,然后只获取所需的资源。有没有更好的方法(最好不要太老套)?

共有3个答案

齐修贤
2023-03-14

似乎有以下工作:

public String[] getResourcesNames(String path) {
    try {
        URL url = getClassLoader().getResource(path);
        if (url == null) {
            return null;
        }

        URI uri = url.toURI();
        if (uri.getScheme().equals("jar")) { // Run from jar
            try (FileSystem fileSystem = FileSystems.newFileSystem(uri, Collections.emptyMap())){
                Path resourcePath = fileSystem.getPath(path);

                // Get all contents of a resource (skip resource itself), if entry is a directory remove trailing /
                List<String> resourcesNames =
                        Files.walk(resourcePath, 1)
                                .skip(1)
                                .map(p -> {
                                    String name = p.getFileName().toString();
                                    if (name.endsWith("/")) {
                                        name = name.substring(0, name.length() - 1);
                                    }
                                    return name;
                                })
                                .sorted()
                                .collect(Collectors.toList());

                return resourcesNames.toArray(new String[resourcesNames.size()]);
            }
        } else { // Run from IDE
            File resource = new File(uri);
            return resource.list();
        }
    } catch (IOException | URISyntaxException e) {
        return null;
    }
}

private ClassLoader getClassLoader() {
    return Thread.currentThread().getContextClassLoader();
}
阎璞瑜
2023-03-14

jar的问题是,没有文件夹本身,只有条目,而文件夹只是名称中带有尾随斜杠的条目。这可能就是为什么返回jar中的文件夹,而不是从de IDE返回,其中文件夹名称不以/结尾。出于类似的原因,请在IDE上工作,但不要在jar中工作,因为文件夹名称在jar中以斜杠结尾。

Spring基于文件处理资源,如果您尝试获取一个空文件夹作为资源,它将失败,而这个空文件夹通常不会添加到jar中。此外,查找文件夹也不太常见,因为内容在文件中,唯一有用的信息是它包含的文件。

实现这一点的最简单方法是使用dir1模式,因为这将列出所有文件以及dir1目录下包含文件的文件夹。

如果程序是从jar文件执行的,“检测”,也可以选择不同的策略列出文件夹,但这种解决方案甚至更“黑客”。

这里有一个使用第一个选项的示例,patterndir1/***(以防万一):

String folderName = "dir1";
String folderPath = String.format("%s/**", folderName);

Resource[] resources = resolver.getResources(folderPath);
Map<String, Resource> resourceByURI = Arrays.stream(resources)
        .collect(Collectors.toMap(resource -> {
            try {
                return resource.getURI().toString();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }, Function.identity()));

resourceByURI是包含由其URI标识的资源的映射。

Resource folder = resolver.getResource(folderName);
int folderLength = folder.getURI().toString().length();
Map<String, String> subdirectoryByName = resourceByURI.keySet().stream()
        .filter(name -> name.length() > folderLength
                && name.indexOf("/", folderLength + 1) == name.length() - 1)
        .collect(Collectors.toMap(Function.identity(), name -> name.substring(folderLength,
                name.indexOf("/", folderLength + 1))));

然后,您可以获取文件夹的URI,计算路径的偏移量(类似于spring所做的),然后检查名称是否比当前文件夹长(在jar中丢弃相同的文件夹),以及名称是否最终包含一个单一的。最后收集到一个由URI再次标识的映射,其中包含文件夹的名称。文件夹名称的集合是子目录byname。values()

孙德宇
2023-03-14

我最终得到了这个(使用Spring):

public class ResourceScanner {
    private PathMatchingResourcePatternResolver resourcePatternResolver;

    public ResourceScanner() {
        this.resourcePatternResolver = new PathMatchingResourcePatternResolver();
    }

    public Resource getResource(String path) {
        path = path.replace("\\", "/");
        return resourcePatternResolver.getResource(path);
    }

    public Resource[] getResources(String path) throws IOException {
        path = path.replace("\\", "/");
        return resourcePatternResolver.getResources(path);
    }

    public Resource[] getResourcesIn(String path) throws IOException {
        // Get root dir URI
        Resource root = getResource(path);
        String rootUri =  root.getURI().toString();

        // Search all resources under the root dir
        path = (path.endsWith("/")) ? path + "**" : path + "/**";

        // Filter only direct children
        return Arrays.stream(getResources(path)).filter(resource -> {
            try {
                String uri = resource.getURI().toString();

                boolean isChild = uri.length() > rootUri.length() && !uri.equals(rootUri + "/");
                if (isChild) {
                    boolean isDirInside = uri.indexOf("/", rootUri.length() + 1) == uri.length() - 1;
                    boolean isFileInside = uri.indexOf("/", rootUri.length() + 1) == -1;
                    return isDirInside || isFileInside;
                }

                return false;
            } catch (IOException e) {
                return false;
            }
        }).toArray(Resource[]::new);
    }

    public String[] getResourcesNamesIn(String path) throws IOException {
        // Get root dir URI
        Resource root = getResource(path);
        String rootUri = URLDecoder.decode(root.getURI().toString().endsWith("/") ? root.getURI().toString() : root.getURI().toString() + "/", "UTF-8");

        // Get direct children names
        return Arrays.stream(getResourcesIn(path)).map(resource -> {
            try {
                String uri = URLDecoder.decode(resource.getURI().toString(), "UTF-8");

                boolean isFile = uri.indexOf("/", rootUri.length()) == -1;
                if (isFile) {
                    return uri.substring(rootUri.length());
                } else {
                    return uri.substring(rootUri.length(), uri.indexOf("/", rootUri.length() + 1));
                }
            } catch (IOException e) {
                return null;
            }
        }).toArray(String[]::new);
    }
}
 类似资料:
  • 源代码是一个Java Maven项目。 Java resources目录包含包含配置文件的子目录。配置文件可以作为维护过程添加和删除。不应知道的文件名。 我如何获得一个提到的项目“资源”目录中的所有文件的列表? 路径是“resources”目录中的文件夹名。

  • 问题内容: 我正在尝试获取资源的途径,但是我没有运气。 这是可行的(在IDE和JAR中都可以),但是这样一来,我无法获取文件的路径,只能获取文件内容: 如果我这样做: 结果是: 有没有办法获取资源文件的路径? 问题答案: 这是故意的。“文件”的内容可能无法作为文件使用。请记住,您正在处理的类和资源可能是JAR文件或其他类型的资源的一部分。类加载器不必为资源提供文件句柄,例如jar文件可能尚未扩展为

  • 问题内容: 我知道还有其他针对同一问题的问题,但问题是解决方案对我不起作用。我有一个小工具,它应该读取我想拥有的文件并将其打包为资源,并依赖于其他我希望将其作为jar而不是单个类的项目(我正在使用Eclipse Helios)。 作为Eclipse中的应用程序,我可以通过以下方式访问资源 当且仅当将资源文件夹放置在输出路径(已编译的源)下时,并且如果将其放置在src文件夹中时,则不是这样。 当我打

  • 问题内容: 我想像这样从我的jar中读取资源: //Read the file 并且在Eclipse中运行它时效果很好,但是如果我将其导出到jar中运行,则会出现: 我真的不知道为什么,但是经过一些测试,我发现我是否改变了 至 然后它的作用相反(它在jar中起作用,但在Eclipse中不起作用)。 我正在使用Eclipse,并且包含我的文件的文件夹位于类文件夹中。 问题答案: 而不是尝试将资源作为

  • 问题内容: 我有一个带有工具栏的Java项目,该工具栏上带有图标。这些图标存储在名为resources /的文件夹中,因此路径可能是“ resources / icon1.png”。该文件夹位于我的src目录中,因此在编译后,该文件夹将被复制到bin / 我正在使用以下代码访问资源。 (imageName将为“ resources / icon1.png”等)。在Eclipse中运行时,效果很好。

  • 问题内容: 我需要读取代码中的文件。它实际上位于此处: 我将其放在源包中,以便在创建可运行的jar文件(导出-> Runnable JAR文件)时将其包含在jar中。最初,我将其放在项目根目录中(并尝试了一个普通的子文件夹),但导出文件并未将其包含在jar中。 如果在我的代码中,我这样做: jar文件正确地找到了该文件,但是在本地运行(运行方式-> Java Main应用程序)会引发文件未找到异常