72

我已将我的应用程序部署到 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
  //....
}
4

6 回答 6

116

你不可以做这个

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

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

但是你可以这样打开一个InputStream

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

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

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

于 2012-04-13T16:32:11.283 回答
21

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

File f = new File(getClass().getResource("/MyResource").toExternalForm());
于 2016-06-21T15:26:41.440 回答
11

这是 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();
}

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

于 2014-05-30T11:04:57.227 回答
1

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

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

而不是代码:

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

解决问题

于 2019-01-25T03:22:11.613 回答
0

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

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

Eclipse-BundleShape: dir

到你的MANIFEST.MF.

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

于 2014-03-10T16:32:43.957 回答
0

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

甚至还提交了一个错误 UNI-197 。

于 2017-05-12T14:22:31.777 回答