在命令行上 运行 时使用 getResourceAsStream() 列出文件为空

Listing files with getResourceAsStream() is empty when run on command line

我正在尝试列出我应用程序的 jar 文件中特定路径的文件。它在我使用 "mvn clean package" 构建时有效,但是当我在命令行上使用 "java -jar target/myproject_1.0.jar" 运行 时,文件列表为空。基于 this suggestion,我正在使用此代码

读取目录内容
    boolean failed = true;
    String schemaLocation = "/xml";
    System.out.println("Scanning folder "+schemaLocation);
    InputStream dirStream = getClass().getResourceAsStream(schemaLocation);
    BufferedReader dirReader = new BufferedReader(new InputStreamReader( dirStream ));
    try{
        String filename = dirReader.readLine();
        while( filename != null ){
            failed = false;
            if( filename.endsWith(".xsd")){
                String fullname = schemaLocation+"/"+filename;
                System.out.println("Loading schema file "+fullname );
                InputStream in = getClass().getResourceAsStream(schemaLocation+"/"+filename);
                readAndProcessSchema(in);
            }
            filename = dirReader.readLine();
        }
    }catch(IOException ex){
        ex.printStackTrace();
    }
    if(failed){
        System.out.println("Fallback enabled.");
        InputStream in = getClass().getResourceAsStream(schemaLocation+"/schema_v1.0.xsd");
        readAndProcessSchema(in);
    }

请注意,流不是空的,只是空的。只有路径列表逻辑失败,因为代码示例末尾的回退代码(读取硬编码的 xsd 文件名)甚至在命令行上也能正常工作。我也尝试了 MyClass.class.getResourceAsStream("/xml")(基于 this suggestion),结果相同。

另一个可能相关的注释是 xml 路径的内容来自我项目的一个依赖项,我无法预测他们将来可能添加哪些额外的文件(因此我需要扫描那条路径)。为了引入这些依赖项,我使用了 this post 的建议,我相信它是有效的,因为 jar 文件 table-of-contents 似乎包含所有内容:

 $ jar -tvf target/myproject-1.0.jar | grep xml
      0 Tue Oct 10 10:02:28 PDT 2017 xml/
   1999 Tue Oct 10 10:02:28 PDT 2017 xml/schema_v1.0.xsd
   4474 Tue Oct 10 10:02:28 PDT 2017 xml/schema_v2.0.xsd
   5757 Fri Oct 06 16:07:48 PDT 2017 META-INF/maven/com.mycompany/myproject/pom.xml

可能还值得一提的是,这是 运行ning 作为 Spring 启动应用程序,使用他们的 spring-boot-maven-plugin "repackage" 目标构建.我现在不仅想知道如何解决这个问题,还想知道为什么类路径在 Maven 单元测试中的工作方式与在命令行中的工作方式不同。

您的代码正在使用 Class#getResourceAsStream,它将使用 class 的 class 加载器。这可能在您的 IDE 或 Maven 中有效,但在其他情况下可能无效。

实际上,您应该尝试使用线程上下文 class 加载程序 Thread.currentThread().getContextClassLoader(),如果失败则回退。

有个类似的问题Get a list of resources from classpath directory

当然,按照那里的建议,您可以使用 Spring 工具,PathMatchingResourcePatternResolver

org.apache.commons.io.IOUtils.toString(getClass().getResourceAsStream("/csv/test.csv"), Charset.forName("UTF-8")))

这是如何访问 jar 文件中的内部源代码的示例。

这很棘手,资源的根路径是什么。在 IDE 中,您可以将某些文件夹(例如 webapp/recource)标记为 resource 文件夹。当您构建 jar 文件时,资源文件夹内容将位于根目录中。因此,如果您从 / 开始您的资源路径,则意味着 jar 的根目录(即资源文件夹的根目录).

我不使用相对路径,因此您可以查看 open resource with relative path in java 以获取更多信息。