Java Jar-файл: использовать ошибки ресурсов: URI не является иерархическим

я развернул свое приложение в файл 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
  //....
}

5 ответов


вы не можете сделать это

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

это не файл! При запуске из ide у вас нет ошибок, потому что вы не запускаете файл jar. В IDE классы и ресурсы извлекаются в файловой системе.

но вы можете открыть InputStream таким образом:

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

удалить "/resource". Как правило, IDEs разделяет классы и ресурсы файловой системы. Но когда кувшин создается, они складываются вместе. Итак, уровень папки "/resource" используется только для разделение классов и ресурсов.

когда вы получаете ресурс из classloader, вы должны указать путь, который ресурс имеет внутри jar, то есть реальную иерархию пакетов.


Если по какой-то причине вам действительно нужно создать java.io.File объект, чтобы указать на ресурс внутри файла Jar, ответ здесь:https://stackoverflow.com/a/27149287/155167

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

вот решение для разработчиков 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) , причина, когда плагин упакован в банку, это заставит Eclipse создать распакованную версию во временном месте, чтобы к объекту можно было получить доступ с помощью файла. Например, я предполагаю, что у Ларса Фогеля есть ошибка в его статье -http://blog.vogella.com/2010/07/06/reading-resources-from-plugin/


пока я сам наткнулся на эту проблему, я хотел бы добавить еще один вариант (в противном случае идеальное объяснение от @dash1e):

экспортируйте плагин как папку (не банку), добавив:

Eclipse-BundleShape: dir

на MANIFEST.MF.

по крайней мере, при экспорте приложения RCP с помощью мастера экспорта (на основе *.product) файл это уважается и будет создавать папку.


в дополнение к общим ответам вы можете получить "URI не является иерархическим" из Unitils библиотека пытается загрузить dataset С . Это может произойти, когда вы храните наборы данных в одном подмодуле maven, но фактические тесты в другом.

есть даже ошибка UNI-197 подано.