Файл 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
  //....
}

Ответ 1

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

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

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

Но вы можете открыть InputStream следующим образом:

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

Удалите "/resource". Как правило, IDE разделяет классы и ресурсы файловой системы. Но когда создается банка, они объединяются. Таким образом, уровень папки "/resource" используется только для разделения классов и ресурсов.

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

Ответ 2

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

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

Ответ 3

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

Ответ 4

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

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

Eclipse-BundleShape: dir

на ваш MANIFEST.MF.

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

Ответ 5

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

Существует даже ошибка UNI-197.

Ответ 6

У меня были похожие проблемы раньше, и я использовал код:

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

вместо кода:

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

решить проблему