【问题标题】:Java Jar file: use resource errors: URI is not hierarchicalJava Jar 文件:使用资源错误:URI 不是分层的
【发布时间】:2012-04-26 00:24:39
【问题描述】:

我已将我的应用程序部署到 jar 文件中。当我需要将数据从一个资源文件复制到 jar 文件之外时,我执行以下代码:

URL resourceUrl = getClass().getResource("/resource/data.sav");
File src = new File(resourceUrl.toURI()); //ERROR HERE
File dst = new File(CurrentPath()+"data.sav");  //CurrentPath: path of jar file don't include jar file name
FileInputStream in = new FileInputStream(src);
FileOutputStream out = new FileOutputStream(dst);
 // some excute code here

我遇到的错误是:URI is not hierarchical。我在 IDE 中运行时没有遇到这个错误。

如果我将上述代码更改为对 StackOverFlow 上其他帖子的帮助:

InputStream in = Model.class.getClassLoader().getResourceAsStream("/resource/data.sav");
File dst = new File(CurrentPath() + "data.sav");
FileOutputStream out = new FileOutputStream(dst);
//....
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) { //NULL POINTER EXCEPTION
  //....
}

【问题讨论】:

    标签: java deployment resources executable-jar


    【解决方案1】:

    你不能这样做

    File src = new File(resourceUrl.toURI()); //ERROR HERE
    

    它不是一个文件! 当您从 ide 运行时,您没有任何错误,因为您没有运行 jar 文件。在 IDE 中的类和资源被提取到文件系统上。

    但是你可以这样打开InputStream

    InputStream in = Model.class.getClassLoader().getResourceAsStream("/data.sav");
    

    删除"/resource"。通常,IDE 将文件系统类和资源分开。但是当罐子被创建时,它们被放在一起。所以文件夹级别"/resource"只用于类和资源的分离。

    当你从类加载器获取资源时,你必须指定资源在 jar 中的路径,即真正的包层次结构。

    【讨论】:

    • 发布项目的层次结构
    • 但是如果我真的需要一个“文件”对象...?
    • @Daniel 这取决于您将资源放在哪里。如果将资源文件放在类文件的同一个包中,则可以使用 data.sav 而不使用起始 /。但在问题中,data.sav 位于根包中,因此在这种情况下,他需要在前面加上 /
    • 就像 TekTimmy:但是如果我真的需要一个文件怎么办?我正在发送电子邮件,我们想将徽标文件图片加入电子邮件。图片在 jar 中,我必须将它作为文件而不是 InputStream 提供给数据源...
    • @JNGerbaux 我还想要一个File 对象,所以我创建了临时File 并将InputStream 中的内容复制到文件对象。使用FileUtils.copyInputStreamToFile(inputStream, file);
    【解决方案2】:

    如果由于某种原因您确实需要创建一个java.io.File 对象来指向 Jar 文件中的资源,答案就在这里:https://stackoverflow.com/a/27149287/155167

    File f = new File(getClass().getResource("/MyResource").toExternalForm());
    

    【讨论】:

      【解决方案3】:

      这是 Eclipse RCP / 插件开发人员的解决方案:

      Bundle bundle = Platform.getBundle("resource_from_some_plugin");
      URL fileURL = bundle.getEntry("files/test.txt");
      File file = null;
      try {
         URL resolvedFileURL = FileLocator.toFileURL(fileURL);
      
         // We need to use the 3-arg constructor of URI in order to properly escape file system chars
         URI resolvedURI = new URI(resolvedFileURL.getProtocol(), resolvedFileURL.getPath(), null);
         File file = new File(resolvedURI);
      } catch (URISyntaxException e1) {
          e1.printStackTrace();
      } catch (IOException e1) {
          e1.printStackTrace();
      }
      

      使用FileLocator.toFileURL(fileURL) 而不是resolve(fileURL) 非常重要 , 因为当插件被打包到一个 jar 中时,这将导致 Eclipse 在一个临时位置创建一个解压版本,以便可以使用 File 访问该对象。例如,我猜 Lars Vogel 在他的文章中有一个错误 - http://blog.vogella.com/2010/07/06/reading-resources-from-plugin/

      【讨论】:

      • 什么是平台类?需要一些非 rt 库吗?
      • @AndreyP 此解决方案适用于 eclipse rcp 插件开发人员。我建议尝试 getResourceAsStream(...) 方法
      • 在我的 maven 构建的 RCP E4 应用程序中,需要提取和打开 jar 捆绑的二进制文件。您的解决方案最终使我能够这样做并在操作系统默认浏览器中打开 file.getAbsolutePath()
      • 谢谢!这个答案非常有帮助,因为我遇到了 FileLocator.resolve 的错误。我可以直接创建 File 对象:File f = new File(FileLocator.toFileURL(resolvedFileURL).toURI());
      【解决方案4】:

      我之前遇到过类似的问题,我用了代码:

      new File(new URI(url.toString().replace(" ","%20")).getSchemeSpecificPart());
      

      代替代码:

      new File(new URI(url.toURI())
      

      解决问题

      【讨论】:

        【解决方案5】:

        虽然我自己偶然发现了这个问题,但我想添加另一个选项(对于@dash1e 的完美解释):

        通过添加将插件导出为文件夹(而不是 jar):

        Eclipse-BundleShape: dir
        

        到您的MANIFEST.MF

        至少当您使用导出向导(基于*.product)文件导出您的 RCP 应用程序时,这会得到尊重并生成一个文件夹。

        【讨论】:

          【解决方案6】:

          除了一般答案之外,您还可以从 Unitils 库尝试从 .jar 文件中加载 数据集 获得“URI 不是分层的”。当您将数据集保存在一个 Maven 子模块中,但在另一个子模块中进行实际测试时,可能会发生这种情况。

          甚至还有一个bug UNI-197 归档。

          【讨论】:

            猜你喜欢
            • 2013-05-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-06-03
            • 1970-01-01
            相关资源
            最近更新 更多