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

查找文件系统资源的相对路径(Spring Boot)

东方嘉佑
2023-03-14

在Spring中,我可以通过指定相对于src/main/resources/目录的路径来访问资源。例如,如果我要求/public/index。html,我将得到一个表示/Users/…的文件系统资源/src/main/resources/public/index。html。然而,我看不到相反的方向。

给定一个文件系统资源,是否有办法找到它相对于src/main/resources/的路径?

我正在使用PathMatchingResourcePattern Resolver来获取我的应用程序中的文件资源列表。我需要的资源位于我的应用程序的文件夹中。

ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
for (Resource r : resolver.getResources("/public/**")) {
    // r.getURI().getString() gives me the absolute path.
}

我可以很容易地得到绝对路径,但是我想找到一种方法来获得从/public/开始的部分,因为Spring就是这样发现它的。

共有1个答案

金阳曜
2023-03-14

我正要问如何做到这一点,用一种比我的解决方案更简单的方式(另外还要处理ClassPathResources,这在我的情况下可能会发生)。下面是我的答案和问题:

ResourcePatternResolver返回的资源。getResources可以是文件系统资源类路径资源,具体取决于glob模式是否包含通配符。(在我的例子中,glob模式是作为参数给出的,应该支持任何模式。)所以,没有getFile;对于这两种方法,唯一可用的路径信息似乎是getDescription

为了确定根目录的深度,我在那个里放了一个参考文件“input files.txt”。这是因为我认为根目录资源“classpath:/input files/”在基于jar的类路径的情况下不需要存在。使用根深度,我可以从资源描述中删除那么多目录。

有人知道一个更简单或不太老套的解决方案吗?

与我的类似,它应该同时使用jar和基于目录的类路径。

import java.io.IOException;
import java.nio.file.Path;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.inject.Inject;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ApplicationContext;
import org.springframework.core.io.Resource;

public class TestClasspathRelativePath implements CommandLineRunner {

    private static final String RESOURCE_ROOT = "classpath:/input-files/";
    private static final String RESOURCE_ROOT_MARKER_FILE = "input-files.txt";
    private static final String FILE_SEPARATOR_PATTERN = "[/\\\\]+";

    @Inject
    private ApplicationContext appContext;

    public static void main(String[] args) {
        new SpringApplicationBuilder()
                .sources(TestClasspathRelativePath.class)
                .html" target="_blank">web(false)
                .build()
                .run("**/*");
    }

    @Override
    public void run(String... args) throws Exception {
        for (String templateFilenamePattern : args) {
            for (Resource template : appContext.getResources(RESOURCE_ROOT + templateFilenamePattern)) {
                createInputFile(template);
            }
        }
    }

    private void createInputFile(Resource template) throws IOException {

        // A resource whose immediate parent is the root input
        // files directory, without wildcard lookup. (As of Spring 4.3.14, with
        // a directory classpath entry, this is a ClassPathResource.)
        Resource topLevelFile = appContext.getResource(RESOURCE_ROOT + RESOURCE_ROOT_MARKER_FILE);

        // A resource whose immediate parent is the root input
        // files directory, with wildcard lookup. (As of Spring 4.3.14, with a
        // directory classpath entry, this is a FileSystemResource.)
        Resource wildcardTopLevelFile =
                // match with min description length is
                // RESOURCE_ROOT/input-files.txt (probably sole match anyway)
                Stream.of(appContext.getResources(RESOURCE_ROOT + "**/" + RESOURCE_ROOT_MARKER_FILE)).min(
                        (r1, r2) -> Integer.valueOf(r1.getDescription().length()).compareTo(Integer.valueOf(r2.getDescription().length())))
                        .orElseThrow(() -> new IllegalStateException("resource " + RESOURCE_ROOT + "/" + RESOURCE_ROOT_MARKER_FILE + " not found"));

        // In the real program, both top level resources are computed only once and on-demand.

        String targetFilename = "<target-dir>/input/" + relativize(template, topLevelFile, wildcardTopLevelFile);
        System.out.println(targetFilename);
        // ... read template, process, write results to targetFilename
    }

    /**
     * Replacement for {@link Path#relativize(Path)} which should also work with
     * non-file resources.
     */
    private static String relativize(Resource child, Resource... topLevelFiles) {
        // find the top-level file for child's type
        Resource referenceFile = Stream.of(topLevelFiles)
                .filter(f -> f.getClass().isInstance(child))
                .findFirst()
                .orElseThrow(() -> new IllegalStateException("don't know how to relativize " + child));
        int rootLevel = descriptionUpToName(referenceFile).split(FILE_SEPARATOR_PATTERN, -1).length - 1;
        return Stream.of(descriptionUpToName(child).split(FILE_SEPARATOR_PATTERN, -1)).skip(rootLevel)
                .collect(Collectors.joining("/"));
    }

    /**
     * Hack to strip the suffix after the name from a resource description. The
     * prefix need not be stripped, because
     * {@link #relativize(Resource, Resource...)} uses a safer way to get rid of
     * that.
     *
     * @return e.g. "file [C:\foo\classpath\input-files\a\b.txt" if the
     *         resource's description is "file
     *         [C:\foo\classpath\input-files\a\b.txt]"
     */
    private static String descriptionUpToName(Resource resource) {
        String path = resource.getDescription();
        int i = path.lastIndexOf(resource.getFilename());
        return path.substring(0, i + resource.getFilename().length());
    }
}
 类似资料:
  • 我试图在服务器上的web应用程序中读取一个本地文件。在JBoss部署之外测试时,文件路径是正确的。然而,当我将它部署到JBoss时,文件路径改变了JBoss的< code>bin目录。当< code>user.dir系统属性被部署为war时,它会发生变化。 我如何在不使用绝对文件路径的情况下防止这种情况? 我想避免绝对文件路径,因为项目需要在具有不同目录结构的多台机器上复制。

  • #include <stdio.h> #include <time.h> int main(void) { time_t now = time(NULL); struct tm local = {0}; struct tm gmt = {0}; localtime_r(&now, &local); gmtime_r

  • 如果我使用它在。很少有像sonar、coverity这样的工具会因为使用它而带来严重的资源泄漏问题。 如果我将其替换为所有这些工具都会悄悄地接受这一点,并且不会出现错误或资源泄漏警告。 如果我们看到,它实际上是在做 我在这里的问题是,java如何处理的资源泄漏,因为代码完全相同,但我们没有引用来显式关闭它?

  • 使用Spring护套。我正在尝试使用Apache POI库解析项目中本地存储的excel文件。我的目录结构如下: > src > 主要 > java语言 com.app 控制器 模型 存储 库 资源 静态 测试.xlsx 我已经尝试了以上两种访问文件的方法,并且尝试了许多不同的文件路径,但是都没有效果。我没有得到构建错误或运行时错误,只是没有找到文件,当我试图调用该方法时,我在那一行得到一个Nul

  • 问题内容: 我希望我的Web应用程序使用以下路径登录文件:webapp / logs / 我可以在log4j.properties文件中设置绝对路径,但是生产环境的目录结构将有所不同。有什么办法可以做到吗? 这是我的方法: 这是将日志打印到我的eclipse目录(c:// eclipse)中名为log.log的文件中。我正在使用Tomcat 6。 问题答案: log4j能够扩展系统属性,因此,如果

  • 我正在尝试使用相对路径在main方法中从我的资源文件夹中获取一个JSON文件。代码使用绝对路径工作,但一旦我从我的项目构建了一个jar文件,这就是我想要的。 Read调用数据库中的一个方法,该方法使用inputstream读取文件。 我得到的错误如下: 编辑(25/09):如果我使用GetResourceStream而不是getResource,我将得到以下错误: