Вопрос-ответ

How to get the path of a running JAR file?

Как получить путь к запущенному JAR-файлу?

Мой код выполняется, скажем, внутри файла JAR foo.jar, и мне нужно знать в коде, в какой папке находится запущенный файл foo.jar.

Итак, если foo.jar находится в C:\FOO\, я хочу получить этот путь независимо от того, какой у меня текущий рабочий каталог.

Переведено автоматически
Ответ 1
return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation()
.toURI()).getPath();

Замените "MyClass" именем вашего класса.

Очевидно, что это приведет к странным вещам, если ваш класс был загружен не из файла.

Ответ 2

Лучшее решение для меня:

String path = Test.class.getProtectionDomain().getCodeSource().getLocation().getPath();
String decodedPath = URLDecoder.decode(path, "UTF-8");

Это должно решить проблему с пробелами и специальными символами.

Ответ 3

Чтобы получить File для данного Class файла, выполните два шага:


  1. Преобразуйте Class в URL

  2. Преобразуйте URL в File

Важно понимать оба шага и не смешивать их.

Получив File, вы можете вызвать getParentFile, чтобы получить содержащую папку, если это то, что вам нужно.

Шаг 1: Class чтобы URL

Как обсуждалось в других ответах, есть два основных способа найти URL относящийся к a Class.


  1. URL url = Bar.class.getProtectionDomain().getCodeSource().getLocation();


  2. URL url = Bar.class.getResource(Bar.class.getSimpleName() + ".class");


У обоих есть плюсы и минусы.

getProtectionDomain Подход выдает базовое местоположение класса (например, содержащий JAR-файл). Однако возможно, что политика безопасности среды выполнения Java выдаст ошибку SecurityException при вызове getProtectionDomain(), поэтому, если вашему приложению необходимо работать в различных средах, лучше всего протестировать во всех из них.

getResource Подход выдает полный путь к ресурсу URL класса, с помощью которого вам нужно будет выполнить дополнительные манипуляции со строками. Это может быть file: путь, но это также может быть jar:file: или даже что-то более неприятное, как bundleresource://346.fwk2106232034:4/foo/Bar.class при выполнении в рамках OSGi. И наоборот, getProtectionDomain подход корректно выдает file: URL-адрес даже из OSGi.

Обратите внимание, что оба getResource("") и getResource(".") завершились ошибкой в моих тестах, когда класс находился внутри JAR-файла; оба вызова вернули null. Поэтому я рекомендую вместо этого вызов # 2, показанный выше, поскольку он кажется более безопасным.

Шаг 2: URL чтобы File

В любом случае, как только у вас будет URL, следующим шагом будет преобразование в File. Это отдельная проблема; смотрите Сообщение в блоге Кохсуке Кавагучи об этом для получения полной информации, но, вкратце, вы можете использовать new File(url.toURI()) при условии, что URL полностью правильно сформирован.

Наконец, я бы настоятельно не рекомендовал использовать URLDecoder. Некоторые символы URL, : и / в частности, недопустимые символы в кодировке URL. Из URLDecoder Javadoc:


Предполагается, что все символы в закодированной строке являются одним из следующих: от "a" до "z", от "A" до "Z", от "0" до "9", и "-", "_", ".", и "*". Символ "%" разрешен, но интерпретируется как начало специальной экранируемой последовательности.


...


Есть два возможных способа, которыми этот декодер мог бы обрабатывать недопустимые строки. Он мог бы либо оставить недопустимые символы в покое, либо выдать исключение IllegalArgumentException . Какой подход использует декодер, зависит от реализации.


На практике, URLDecoder как правило, не выдает ошибкуIllegalArgumentException, как угрожалось выше. И если ваш путь к файлу содержит пробелы, закодированные как %20, этот подход может показаться работающим. Однако, если ваш путь к файлу содержит другие не буквенные символы, такие как + у вас возникнут проблемы с URLDecoder искажением пути к файлу.

Рабочий код

Для выполнения этих шагов у вас могут быть методы, подобные следующим:

/**
* Gets the base location of the given class.
* <p>
* If the class is directly on the file system (e.g.,
* "/path/to/my/package/MyClass.class") then it will return the base directory
* (e.g., "file:/path/to").
* </p>
* <p>
* If the class is within a JAR file (e.g.,
* "/path/to/my-jar.jar!/my/package/MyClass.class") then it will return the
* path to the JAR (e.g., "file:/path/to/my-jar.jar").
* </p>
*
* @param c The class whose location is desired.
* @see FileUtils#urlToFile(URL) to convert the result to a {@link File}.
*/

public static URL getLocation(final Class<?> c) {
if (c == null) return null; // could not load the class

// try the easy way first
try {
final URL codeSourceLocation =
c.getProtectionDomain().getCodeSource().getLocation();
if (codeSourceLocation != null) return codeSourceLocation;
}
catch (final SecurityException e) {
// NB: Cannot access protection domain.
}
catch (final NullPointerException e) {
// NB: Protection domain or code source is null.
}

// NB: The easy way failed, so we try the hard way. We ask for the class
// itself as a resource, then strip the class's path from the URL string,
// leaving the base path.

// get the class's raw resource path
final URL classResource = c.getResource(c.getSimpleName() + ".class");
if (classResource == null) return null; // cannot find class resource

final String url = classResource.toString();
final String suffix = c.getCanonicalName().replace('.', '/') + ".class";
if (!url.endsWith(suffix)) return null; // weird URL

// strip the class's path from the URL string
final String base = url.substring(0, url.length() - suffix.length());

String path = base;

// remove the "jar:" prefix and "!/" suffix, if present
if (path.startsWith("jar:")) path = path.substring(4, path.length() - 2);

try {
return new URL(path);
}
catch (final MalformedURLException e) {
e.printStackTrace();
return null;
}
}

/**
* Converts the given {@link URL} to its corresponding {@link File}.
* <p>
* This method is similar to calling {@code new File(url.toURI())} except that
* it also handles "jar:file:" URLs, returning the path to the JAR file.
* </p>
*
* @param url The URL to convert.
* @return A file path suitable for use with e.g. {@link FileInputStream}
* @throws IllegalArgumentException if the URL does not correspond to a file.
*/

public static File urlToFile(final URL url) {
return url == null ? null : urlToFile(url.toString());
}

/**
* Converts the given URL string to its corresponding {@link File}.
*
* @param url The URL to convert.
* @return A file path suitable for use with e.g. {@link FileInputStream}
* @throws IllegalArgumentException if the URL does not correspond to a file.
*/

public static File urlToFile(final String url) {
String path = url;
if (path.startsWith("jar:")) {
// remove "jar:" prefix and "!/" suffix
final int index = path.indexOf("!/");
path = path.substring(4, index);
}
try {
if (PlatformUtils.isWindows() && path.matches("file:[A-Za-z]:.*")) {
path = "file:/" + path.substring(5);
}
return new File(new URL(path).toURI());
}
catch (final MalformedURLException e) {
// NB: URL is not completely well-formed.
}
catch (final URISyntaxException e) {
// NB: URL is not completely well-formed.
}
if (path.startsWith("file:")) {
// pass through the URL as-is, minus "file:" prefix
path = path.substring(5);
return new File(path);
}
throw new IllegalArgumentException("Invalid URL: " + url);
}

Вы можете найти эти методы в общей библиотеке SciJava:

Ответ 4

Вы также можете использовать:

CodeSource codeSource = YourMainClass.class.getProtectionDomain().getCodeSource();
File jarFile = new File(codeSource.getLocation().toURI().getPath());
String jarDir = jarFile.getParentFile().getPath();
java jar