【问题标题】:How to reference a resource file correctly for JAR and Debugging?如何为 JAR 和调试正确引用资源文件?
【发布时间】:2011-09-05 18:22:59
【问题描述】:

在使用 Maven 项目和 Jar 文件时,我遇到了一个严重的资源引用问题...

我将所有资源都放在一个专用文件夹 /src/main/resources 中,该文件夹是 Eclipse 中构建路径的一部分。使用

引用文件
getClass().getResource("/filename.txt")

这在 Eclipse 中运行良好,但在 Jar 文件中失败 - 资源位于 jar 根目录正下方的文件夹中...

有谁知道在 Eclipse 中引用 JAR 和 (!) 中的文件的“最佳实践”?

编辑: 问题是,虽然资源实际上位于顶层文件夹“资源”中的 JAR 中,但上述方法无法找到该文件...

【问题讨论】:

  • jar 文件中使用的文件夹是什么? /资源?
  • 这在 Eclipse 中工作正常,但在 Jar 文件中失败 - 资源位于 jar 根目录正下方的文件夹中...... 这正是应该发生的。问题出在哪里?
  • 无论是从 IDE 还是从“JAR”运行代码,您都应该以相同的方式开发 - 即,如果您希望从 IDE 中的类路径加载资源,您应该能够加载在外部运行时也来自类路径的资源!
  • 完全相同的行(当时也使用该文件)引发异常(NullPointer)-因此找不到该文件...尽管它实际上是存在的!

标签: java eclipse jar


【解决方案1】:

打包 JAR 后,您的资源文件不再是文件,而是流,因此 getResource 将不起作用!

使用getResourceAsStream。

要获取“文件”内容,请使用https://commons.apache.org/proper/commons-io/javadocs/api-release/org/apache/commons/io/IOUtils.html:

static public String getFile(String fileName)
{
        //Get file from resources folder
        ClassLoader classLoader = (new A_CLASS()).getClass().getClassLoader();

        InputStream stream = classLoader.getResourceAsStream(fileName);

        try
        {
            if (stream == null)
            {
                throw new Exception("Cannot find file " + fileName);
            }

            return IOUtils.toString(stream);
        }
        catch (Exception e) {
            e.printStackTrace();

            System.exit(1);
        }

        return null;
}

【讨论】:

  • 这应该是公认的答案。它解释了为什么 getResource 不起作用并列出了替代方案,如果您需要它们,但坦率地说,将其包装在 InputStreamReader 中可以正常工作。
  • 在某处是否有针对此行为的 Java 文档?我在这个问题上花了太多时间......
【解决方案2】:

我遇到了类似的问题。 经过一整天的尝试每种组合和调试后,我尝试了 getClass().getResourceAsStream("resources/filename.txt") 并最终让它工作。 没有其他帮助。

【讨论】:

  • getResourceAsStream 确实值得一试,而不仅仅是为了缩短您的代码。对我来说ThatClass.class.getClassLoader().getResourceAsStream("filename.txt") 工作。前缀“资源”对我来说没有意义,因为文件已复制到 JAR 的根目录。不过要记住的一件事是getResourceAsStream 不会抛出异常,但如果找不到文件,则returns null。
  • 谢谢,@YushinWashio 这正是我所需要的。
【解决方案3】:

Maven 资源文件夹的内容被复制到目标/类,并从那里复制到生成的 Jar 文件的根目录。这是预期的行为。

我不明白您的方案中存在什么问题。通过getClass().getResource("/filename.txt") 引用资源从类路径的根开始,无论它(或其元素)是target/classes 还是JAR 的根。我看到的唯一可能的错误是您使用了错误的ClassLoader。

确保使用资源的类与资源在同一个工件 (JAR) 中并执行ThatClass.class.getResource("/path/with/slash") 或ThatClass.class.getClassLoader().getResource("path/without/slash")。

但除此之外:如果它不起作用,您可能在构建过程中的某个地方做错了什么。你能验证资源在 JAR 中吗?

【讨论】:

  • 听起来他的资源文件没有被编译到 JAR 中,不知何故
  • 啊,重要的部分丢失了,对不起:文件实际上在 JAR 中,但是由于使用 getClass().getResource("/filename.txt 找不到文件,所以出现 NullPointerException ")...
  • @Patrick 你确定你使用的是正确的大小写吗?如果你使用windows,文件系统不区分大小写,但是一个JAR文件是...
  • @Sean:是的,他们都在使用 camelCase。我再次检查,但它们似乎是正确的......
  • 谢谢,getClass().getResourceAsStream("/folder/file.xml") - 为我工作!
【解决方案4】:

如果您在 jar 文件中添加资源目录(因此它位于 jar 中的 /resources 文件夹下,并且如果 /src/main 在 eclipse 中的构建路径中,那么您应该能够将您的文件引用为:

getClass().getResource("/resources/filename.txt");  

应该在两种环境中都可以使用。

【讨论】:

  • 该文件夹在 jar 中,并且 Eclipse 中的构建路径设置为包含资源文件夹,但奇怪的是它不起作用...
  • 省略 /resources 并从 filename.txt 或 foldername/filename.txt 开始对我有用
【解决方案5】:

问题是在 IDE 中 getClass().getResource("Path");访问文件时字符串不区分大小写,但从 jar 运行时它是。与文件相比,检查您在目录上的大小写。它确实有效。此外,如果您尝试 new File(getClass().getResource("Path"); 该文件将无法在 IDE 之外读取。

【讨论】:

    【解决方案6】:

    也许这种方法在某些情况下会有所帮助。

    public static File getResourceFile(String relativePath)
    {
        File file = null;
        URL location = <Class>.class.getProtectionDomain().getCodeSource().getLocation();
        String codeLocation = location.toString();
        try{
            if (codeLocation.endsWith(".jar"){
                //Call from jar
                Path path = Paths.get(location.toURI()).resolve("../classes/" + relativePath).normalize();
                file = path.toFile();
            }else{
                //Call from IDE
                file = new File(<Class>.class.getClassLoader().getResource(relativePath).getPath());
            }
        }catch(URISyntaxException ex){
            ex.printStackTrace();
        }
        return file;
    }
    

    【讨论】:

      【解决方案7】:

      只需将文件复制到临时目录即可。

      String tempDir = System.getProperty("java.io.tmpdir");
      File file = new File(tempDir.getAbsolutePath(), "filename.txt");
      if (!file.exists()) {
           InputStream is = (getClass().getResourceAsStream("/filename.txt"));
           Files.copy(is, file.getAbsoluteFile().toPath());
      }
      

      【讨论】:

      • 这仅在用户有权写入 tmpdir(或您选择的任何其他目录)的情况下才有效 - 特别是当 JAR 文件在许多用户之间共享时。如果资源是只读的,最好让JAR自包含,
      猜你喜欢
      • 2011-11-07
      • 1970-01-01
      • 2011-10-26
      • 1970-01-01
      • 2018-04-26
      • 1970-01-01
      • 1970-01-01
      • 2013-09-03
      • 1970-01-01
      相关资源
      最近更新 更多