Файл 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())
решить проблему