Java Jar文件:使用资源错误:URI不是分层的

hqt*_*hqt 54 java deployment resources executable-jar

我已将我的应用程序部署到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
Run Code Online (Sandbox Code Playgroud)

我遇到的错误是: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
  //....
}
Run Code Online (Sandbox Code Playgroud)

das*_*h1e 92

你不能做这个

File src = new File(resourceUrl.toURI()); //ERROR HERE
Run Code Online (Sandbox Code Playgroud)

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

但你可以InputStream用这种方式打开:

    InputStream in = Model.class.getClassLoader().getResourceAsStream("/data.sav");
Run Code Online (Sandbox Code Playgroud)

删除"/resource".通常,IDE会分离文件系统类和资源.但是当创建jar时,它们会被放在一起.因此文件夹级别"/resource"仅用于类和资源分离.

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

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

Mar*_*rio 14

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

File f = new File(getClass().getResource("/MyResource").toExternalForm());
Run Code Online (Sandbox Code Playgroud)

  • 不起作用。不抓住任何东西 (3认同)

Ily*_*iuk 8

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

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();
}
Run Code Online (Sandbox Code Playgroud)

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

  • @AndreyP 此解决方案适用于 eclipse rcp 插件开发人员。我建议尝试 getResourceAsStream(...) 方法 (2认同)