让我们有一个maven项目,资源包含以下结构:
的src /主/资源
虽然我找到了许多如何列出文件资源的答案,但我仍然坚持找到一种方法如何列出资源中目录(或路径)的所有直接子目录,当从IDE(IntelliJ)运行应用程序时这将起作用和罐子。
目标是获取目录" dir1"的子目录的名称: subdir1,subdir2
我试过
Thread.currentThread().getContextClassLoader().getResourceAsStream("dir1");
并使用返回的InputStream(包含子目录的名称),但不能从jar工作。来自IntelliJ的作品。
我也试过使用spring框架但是
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource[] resources = resolver.getResources("dir1/*");
在jar中不起作用 - resources
数组为空。来自IntelliJ的作品。
我尝试修改为
Resource[] resources = resolver.getResources("dir1/*/");
它可以从jar工作,但不能从IntelliJ工作。
当我从jar工作时,我打破了另一种方式,反之亦然。我的最后一个想法是使用
Resource[] resources = resolver.getResources("dir1/**");
获取目录下的所有资源,然后只获取所需的资源。是否有更好的(最好不是hacky)方式?
答案 0 :(得分:0)
jar的问题在于没有这样的文件夹,有条目,文件夹只是在其名称中带有尾部斜杠的条目。这可能是dir1/*/
返回jar中文件夹而不是文件夹名称不以/
结尾的de IDE的原因。由于类似的原因,dir1/*
在IDE上工作但在jar中没有,因此文件夹名称以jar中的斜杠结尾。
Spring根据文件处理资源,如果你尝试将空文件夹作为资源而失败,那么这个空文件夹通常不会添加到jar中。寻找文件夹并不常见,因为内容在文件中,唯一有用的信息是它包含的文件。
实现此目的的最简单方法是使用dir1/**
模式,因为这将列出所有文件以及包含dir1
目录下文件的文件夹。
'检测'如果正在从jar文件执行程序,选择不同的策略列出文件夹也可以完成,但该解决方案更加“hacky”。
这是一个使用第一个选项的示例,模式dir1/**
(仅在需要的情况下):
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
是一个包含Resource
的地图,由 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标识的Map
,其中包含文件夹的名称。文件夹名称的集合为subdirectoryByName.values()
。
答案 1 :(得分:0)
似乎有以下作品:
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();
}
答案 2 :(得分:0)
我最终以春天告终了:
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);
}
}
答案 3 :(得分:0)
感谢Lubik的第一篇文章,它在IDE或jar中的Springboot 2.1。中运行良好。
我需要从jar(或dev中的IDE)中复制和读取一些资源文件,而是返回Resource [],然后借助resource.getInputStream()将它们复制到磁盘上所需的位置:
for (Resource resource: mapResources) {
Path destPath =
someFolder.resolve(resource.getFilename());
Files.copy(resource.getInputStream(), destPath);
}