Как получить путь к работающему файлу JAR?


580

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

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


Посмотрите ответ Fab для решения, которое работает, когда пути включают пробелы. Также обратите внимание, что некоторые ответы ниже касаются вопроса в заголовке (путь к jar), некоторые - к самому вопросу (путь к папке, содержащей jar), а некоторые предоставляют пути к классам внутри файла jar.
Энди Томас,

32
Осторожно при использовании в ANT! ============== Я называю String path = SomeClass.class.getProtectionDomain (). GetCodeSource (). GetLocation (). GetPath (); и получить: /C:/apache-ant-1.7.1/lib/ant.jar Не очень полезно!
Дино Fancellu

Интересно. Оригинальный код, в котором я это использовал, никогда не запускался в ant, поэтому для меня это не проблема.
Тьяго Чавес

2
@Dino Fancellu, я испытал именно то, что вы описали. Работает во время разработки, не работает при сборке.
Приятель

Ответы:


539
return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation()
    .toURI()).getPath();

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

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


43
Этот toURI()шаг жизненно необходим, чтобы избежать проблем со специальными символами, включая пробелы и плюсы Правильный однострочный: return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().toURI()); использование URLDecoderне работает для многих специальных символов. Смотрите мой ответ ниже для более подробной информации.
ctrueden

4
Примечание: это возвращает путь, включая имя файла jar
Buddy

8
Разве это не указывает на файл jar, а не на работающий каталог? Вам нужно будет сделать результат getParentFile () для этой работы.
FOO

1
Кроме того, getProtectionDomainимеет значение null, если вы получаете свой класс от трассировки:val strace = Thread.currentThread().getStackTrace; val path = strace(1).getClass.getProtectionDomain
bbarker

1
Использование этого метода до Java 8; поместив этот метод в класс, который находится во внешнем Jar-файле, загруженном через class-path, тогда будет указан путь внешнего jar-файла вместо действующего Jar-файла.
Mr00Anderson

189

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

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

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


8
Еще одно примечание: при вызове этой функции из Jar, имя jar добавляется в конце для меня, поэтому пришлось выполнить: path.substring (0, path.lastIndexOf ("/") + 1);
Will824

11
/ не обязательно разделитель пути. Вы должны сделать (новый файл (путь)). GetParentFile (). GetPath () вместо этого.
pjz

10
Здесь нет проблем с добавлением имени файла JAR. UTF-преобразование кажется идеальным решением в сочетании с @Iviggiani one's ( URLDecoder.decode(ClassLoader.getSystemClassLoader().getResource(".").getPath(), "UTF-8");) в Linux. Тем не менее, я не пробовал на Windows.
Ubuntudroid

2
Спасибо, это позволило мне загружать файлы, внешние по отношению к моему JAR, с помощью FileInputStream как в Linux, так и в Windows. Просто нужно было добавить расшифрованный путь перед именем файла ...
giorgio79

11
Осторожно: не рекомендуется использовать URLDecoderдля декодирования специальных символов. В частности, символы like +будут ошибочно декодированы в пробелы. Смотрите мой ответ для деталей.
ctrueden

153

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

  1. Преобразовать Classв аURL
  2. Преобразовать URLв аFile

Важно понимать оба шага, а не объединять их.

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

Шаг 1: ClassвURL

Как обсуждалось в других ответах, есть два основных способа найти URLотношение к 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; оба вызова вернули ноль. Поэтому я рекомендую вызов №2, показанный выше, так как он кажется более безопасным.

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

В любом случае, если у вас есть URL, следующим шагом будет преобразование в File. Это его собственная проблема; см. подробности в блоге Kohsuke Kawaguchi об этом , но вкратце вы можете использовать его, 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 :


5
+1; лучший ответ на сегодняшний день: он вернет путь, используя правильные обозначения для ОС. (например, \ для окон).
Вирсавия

Что касается безопасности, я считаю, что обнаружил, что Java WebStart не допускает этого.
Турбьёрн Равн Андерсен

55

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

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

3
Это работает лучше для меня, потому что это дает путь кувшина, а не класса!
T30

У меня тоже сработало. Объедините с ответом Fab, и это станет лучше!
Даниэльсон Алвес Жуниор

25

Используйте ClassLoader.getResource (), чтобы найти URL для вашего текущего класса.

Например:

package foo;

public class Test
{
    public static void main(String[] args)
    {
        ClassLoader loader = Test.class.getClassLoader();
        System.out.println(loader.getResource("foo/Test.class"));
    }
}

(Этот пример взят из аналогичного вопроса .)

Чтобы найти каталог, вам необходимо вручную разобрать URL. См. Учебник JarClassLoader для формата jar URL.


Мой JAR-файл запутан, поэтому этот ответ не решает мою проблему. Но я не указал это в вопросе, так что это все еще правильный ответ.
Тьяго Чавес

12
Если это запутано, используйте Test.class.getName () и выполните соответствующие действия.
Джон Скит

1
@JonSkeet есть так много проблем с вашим ответом: 1. Не будет, NPEпотому что вы не ответили на вопрос, который был задан (был задан путь к директории JAR, и вы ответили на совершенно другой вопрос: путь к классу). 2. Как указали другие, и у меня возникла та же проблема, она не работает для апплетов. 3. Возвращается путь не канонического представления пути вообще: jar:file:/listener/build/libs/listener-1.0.0-all.jar!/shared/Test.class.
WhiteAngel

1
@WhiteAngel: 1) Последняя строка моего поста указывает на то, что вам нужно просмотреть URL-адрес и выбрать его отдельно, чтобы получить файл JAR. Я согласен , что это не самый полный ответ, но я не думаю , что это на самом деле так плохо стоит спорить о том (особенно 10 лет спустя ...) 2) апплеты не были упомянуты ни в одном комментарии здесь - как ни странно, я не У меня нет времени, чтобы просмотреть все комментарии ко всем ответам на вопросы, на которые я случайно отправил ответ. 3) Опять же, я ссылаюсь на формат URL банку.
Джон Скит

2
@WhiteAngel: Это лучший ответ, который я когда-либо писал? Нет. Это так плохо, как ты думаешь? Нет, я так не думаю. (В частности, с точки зрения заявлений, которые вы выдвинули в связи с тем, что он бросил NPE, а этого нет.) Я бы посоветовал вам добавить свой собственный ответ, а не суетиться по этому поводу. Это был бы более позитивный подход.
Джон Скит

19

Я удивлен, увидев, что никто недавно не предложил использовать Path. Далее следует цитата: « класс включает в себя различные методы , которые могут быть использованы для получения информации о пути, элементы доступа пути, преобразовать путь к другим формам, или экстракт порциям по пути »Path

Таким образом, хорошая альтернатива - получить Pathобъект как:

Path path = Paths.get(Test.class.getProtectionDomain().getCodeSource().getLocation().toURI());

3
Как примечание, Путь доступен начиная с Java 7.
Крис Форренс

15

Единственное решение, которое работает для меня на Linux, Mac и Windows:

public static String getJarContainingFolder(Class aclass) throws Exception {
  CodeSource codeSource = aclass.getProtectionDomain().getCodeSource();

  File jarFile;

  if (codeSource.getLocation() != null) {
    jarFile = new File(codeSource.getLocation().toURI());
  }
  else {
    String path = aclass.getResource(aclass.getSimpleName() + ".class").getPath();
    String jarFilePath = path.substring(path.indexOf(":") + 1, path.indexOf("!"));
    jarFilePath = URLDecoder.decode(jarFilePath, "UTF-8");
    jarFile = new File(jarFilePath);
  }
  return jarFile.getParentFile().getAbsolutePath();
}

Так не пойдет. Если в Linux метод toUri () вызовет исключение, и вы не достигнете другой части, для linux.
Вильгельм Сорбан

9

У меня была та же проблема, и я решил ее так:

File currentJavaJarFile = new File(Main.class.getProtectionDomain().getCodeSource().getLocation().getPath());   
String currentJavaJarFilePath = currentJavaJarFile.getAbsolutePath();
String currentRootDirectoryPath = currentJavaJarFilePath.replace(currentJavaJarFile.getName(), "");

Надеюсь, я вам помог.


Не делай этого. URL.getPath () не возвращает имя файла и завершится ошибкой при многих обстоятельствах, таких как пути к файлам с пробелами в них.
VGR

9

Вот обновление до других комментариев, которые кажутся мне неполными из-за специфики

используя относительную «папку» вне файла .jar (в том же месте jar):

String path = 
  YourMainClassName.class.getProtectionDomain().
  getCodeSource().getLocation().getPath();

path = 
  URLDecoder.decode(
    path, 
    "UTF-8");

BufferedImage img = 
  ImageIO.read(
    new File((
        new File(path).getParentFile().getPath()) +  
        File.separator + 
        "folder" + 
        File.separator + 
        "yourfile.jpg"));

4
Осторожно: не рекомендуется использовать URLDecoderдля декодирования специальных символов. В частности, символы like +будут ошибочно декодированы в пробелы. Смотрите мой ответ для деталей.
ctrueden

Использование специальных символов в именах файлов не рекомендуется.
Зон

URLDecoderнесмотря на свое имя, предназначен для декодирования URL и имен и значений параметров формы, а не URL.
Маркиз Лорн

6

Для получения пути запуска jar-файла я изучил вышеупомянутые решения и перепробовал все методы, которые существуют между собой. Если этот код выполняется в Eclipse IDE, все они должны иметь возможность найти путь к файлу, включая указанный класс, и открыть или создать указанный файл с найденным путем.

Но это сложно, если запустить файл jar, работающий под управлением, напрямую или через командную строку, он потерпит неудачу, так как путь к файлу jar, полученный из вышеуказанных методов, даст внутренний путь в файле jar, то есть он всегда дает путь в виде

rsrc: имя-проекта (возможно, я должен сказать, что это имя пакета файла основного класса - указанный класс)

Я не могу преобразовать путь rsrc: ... во внешний путь, то есть при запуске файла JAR вне Eclipse IDE он не может получить путь к файлу JAR.

Единственный возможный способ получить путь запуска jar-файла вне Eclipse IDE - это

System.getProperty("java.class.path")

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


java.class.pathможет быть многозначным. Одно из этих значений, безусловно, обеспечит каталог или JAR-файл, в котором находится текущий класс, но какой именно?
маркиз Лорн

Я подтверждаю, я пробовал другие решения, но никогда не получал имя файла jar. Это работает очень просто! спасибо - +1
Гийом Жирод-Витучкина

5

Другие ответы, кажется, указывают на источник кода, который является местоположением файла Jar, который не является каталогом.

использование

return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()).getParentFile();

Это может быть каталог, если вы загружаете свои классы из файловой системы вместо файла JAR, например, при отладке.
Маркиз Лорн

4

выбранный выше ответ не работает, если вы запустите свой jar-файл, щелкнув по нему в среде рабочего стола Gnome (а не в любом скрипте или терминале).

Вместо этого мне понравилось, что следующее решение работает везде:

    try {
        return URLDecoder.decode(ClassLoader.getSystemClassLoader().getResource(".").getPath(), "UTF-8");
    } catch (UnsupportedEncodingException e) {
        return "";
    }

2
Вы пробовали это в апплете или приложении. запущен с помощью Java Web Start? Насколько я понимаю, это не удастся в обеих ситуациях (даже если приложение является доверенным).
Эндрю Томпсон

Это решение может только вернуть местоположение "." в файле JAR, а не место в файле JAR.
Маркиз Лорн

Осторожно: не рекомендуется использовать URLDecoderдля декодирования специальных символов. В частности, символы like +будут ошибочно декодированы в пробелы. Смотрите мой ответ для деталей.
ctrueden

Весной загрузится, его NullPointerException
Рави Парех

У вас будет, NPEесли в JAR нет ресурсов.
WhiteAngel

3

На самом деле вот лучшая версия - старая не удалась, если в имени папки был пробел.

  private String getJarFolder() {
    // get name and path
    String name = getClass().getName().replace('.', '/');
    name = getClass().getResource("/" + name + ".class").toString();
    // remove junk
    name = name.substring(0, name.indexOf(".jar"));
    name = name.substring(name.lastIndexOf(':')-1, name.lastIndexOf('/')+1).replace('%', ' ');
    // remove escape characters
    String s = "";
    for (int k=0; k<name.length(); k++) {
      s += name.charAt(k);
      if (name.charAt(k) == ' ') k += 2;
    }
    // replace '/' with system separator char
    return s.replace('/', File.separatorChar);
  }

Что касается неудачи с апплетами, у вас все равно обычно не будет доступа к локальным файлам. Я не знаю много о JWS, но для обработки локальных файлов может быть невозможно загрузить приложение.


Есть несколько встроенных способов декодирования пути. Не нужно писать свой собственный код.
Маркиз Лорн

3

Я попытался получить путь кувшина с помощью

String folder = MyClassName.class.getProtectionDomain().getCodeSource().getLocation().getPath();

c: \ app> java -jar application.jar

Запустив jar-приложение с именем «application.jar», в Windows в папке « c: \ app » значение строковой переменной «folder» было « \ c: \ app \ application.jar », и у меня были проблемы с тестированием для правильность пути

File test = new File(folder);
if(file.isDirectory() && file.canRead()) { //always false }

Поэтому я попытался определить «тест» как:

String fold= new File(folder).getParentFile().getPath()
File test = new File(fold);

чтобы получить путь в правильном формате, например, « c: \ app » вместо « \ c: \ app \ application.jar », и я заметил, что он работает.


3

Самое простое решение - передать путь в качестве аргумента при запуске фляги.

Вы можете автоматизировать это с помощью сценария оболочки (.bat в Windows, .sh в любом другом месте):

java -jar my-jar.jar .

Я использовал .для передачи текущего рабочего каталога.

ОБНОВИТЬ

Возможно, вы захотите вставить файл JAR в подкаталог, чтобы пользователи случайно не щелкали по нему. Ваш код должен также проверить, чтобы убедиться, что аргументы командной строки были предоставлены, и предоставить хорошее сообщение об ошибке, если аргументы отсутствуют.


3

Мне пришлось много возиться, прежде чем я наконец нашел рабочее (и короткое) решение.
Вполне возможно, что jarLocationидет с префиксом вроде file:\или jar:file\, который можно удалить с помощью String#substring().

URL jarLocationUrl = MyClass.class.getProtectionDomain().getCodeSource().getLocation();
String jarLocation = new File(jarLocationUrl.toString()).getParent();

2
String path = getClass().getResource("").getPath();

Путь всегда относится к ресурсу в файле jar.


1
Эта строка пути все еще должна быть упрощена для ваших нужд. String path = new File(getClass().getResource("").getPath()).getParentFile().getParent(); File jarDir = new File(path.substring(5));
ZZZ

4
И то getResource("")и другое getResource(".")не удалось в моих тестах, когда класс находился в файле JAR; оба вызова вернули ноль.
ctrueden

2
Это кидает NullPointerException.
маркиз Лорн

2
public static String dir() throws URISyntaxException
{
    URI path=Main.class.getProtectionDomain().getCodeSource().getLocation().toURI();
    String name= Main.class.getPackage().getName()+".jar";
    String path2 = path.getRawPath();
    path2=path2.substring(1);

    if (path2.contains(".jar"))
    {
        path2=path2.replace(name, "");
    }
    return path2;}

Хорошо работает на Windows


1

Что разочаровывает, так это то, что когда вы разрабатываете в Eclipse, MyClass.class.getProtectionDomain().getCodeSource().getLocation()возвращается /binкаталог, который великолепен, но когда вы компилируете его в jar, путь включает в себя /myjarname.jarчасть, которая дает вам недопустимые имена файлов.

Чтобы код работал как в ide, так и после его компиляции в jar, я использую следующий фрагмент кода:

URL applicationRootPathURL = getClass().getProtectionDomain().getCodeSource().getLocation();
File applicationRootPath = new File(applicationRootPathURL.getPath());
File myFile;
if(applicationRootPath.isDirectory()){
    myFile = new File(applicationRootPath, "filename");
}
else{
    myFile = new File(applicationRootPath.getParentFile(), "filename");
}

1

Не совсем уверен насчет других, но в моем случае это не сработало с «Runnable jar», и я получил его, скомбинировав коды из ответа phchen2 и другого по этой ссылке: Как получить путь к работающему файлу JAR? Код:

               String path=new java.io.File(Server.class.getProtectionDomain()
                .getCodeSource()
                .getLocation()
                .getPath())
          .getAbsolutePath();
       path=path.substring(0, path.lastIndexOf("."));
       path=path+System.getProperty("java.class.path");

1

Опробовали несколько решений, но ни одно из них не дало правильных результатов для (вероятно, особого) случая, когда исполняемый файл jar был экспортирован с помощью «Упаковки внешних библиотек» в Eclipse. По какой-то причине все решения, основанные на ProtectionDomain, в этом случае приводят к нулю.

Комбинируя некоторые решения выше, мне удалось получить следующий рабочий код:

String surroundingJar = null;

// gets the path to the jar file if it exists; or the "bin" directory if calling from Eclipse
String jarDir = new File(ClassLoader.getSystemClassLoader().getResource(".").getPath()).getAbsolutePath();

// gets the "bin" directory if calling from eclipse or the name of the .jar file alone (without its path)
String jarFileFromSys = System.getProperty("java.class.path").split(";")[0];

// If both are equal that means it is running from an IDE like Eclipse
if (jarFileFromSys.equals(jarDir))
{
    System.out.println("RUNNING FROM IDE!");
    // The path to the jar is the "bin" directory in that case because there is no actual .jar file.
    surroundingJar = jarDir;
}
else
{
    // Combining the path and the name of the .jar file to achieve the final result
    surroundingJar = jarDir + jarFileFromSys.substring(1);
}

System.out.println("JAR File: " + surroundingJar);


0

Этот метод, вызываемый из кода в архиве, возвращает папку, в которой находится файл .jar. Он должен работать в Windows или Unix.


  private String getJarFolder() {
    String name = this.getClass().getName().replace('.', '/');
    String s = this.getClass().getResource("/" + name + ".class").toString();
    s = s.replace('/', File.separatorChar);
    s = s.substring(0, s.indexOf(".jar")+4);
    s = s.substring(s.lastIndexOf(':')-1);
    return s.substring(0, s.lastIndexOf(File.separatorChar)+1);
  } 

Получено из кода в: Определите, работает ли из JAR


3
«Это должно работать в Windows или Unix». но потерпит неудачу в любом апплете и каждом приложении. запущен с использованием JWS.
Эндрю Томпсон

0

Стоит упомянуть, что это только проверено, Windowsно я думаю, что оно отлично работает на других операционных системах [ Linux,MacOs,Solaris] :).


У меня было 2 .jar файла в одном каталоге. Я хотел из одного .jarфайла запустить другой .jarфайл, который находится в том же каталоге.

Проблема в том, что при запуске его из cmdтекущего каталога есть system32.


Предупреждение!

  • Приведенное ниже, похоже, работает очень хорошо во всех тестах, которые я провел, даже с именем папки, ;][[;'57f2g34g87-8+9-09!2#@!$%^^&()или ()%&$%^@# он работает хорошо.
  • Я использую ProcessBuilderс ниже следующим:

🍂 ..

//The class from which i called this was the class `Main`
String path = getBasePathForClass(Main.class);
String applicationPath=  new File(path + "application.jar").getAbsolutePath();


System.out.println("Directory Path is : "+applicationPath);

//Your know try catch here
//Mention that sometimes it doesn't work for example with folder `;][[;'57f2g34g87-8+9-09!2#@!$%^^&()` 
ProcessBuilder builder = new ProcessBuilder("java", "-jar", applicationPath);
builder.redirectErrorStream(true);
Process process = builder.start();

//...code

🍂 getBasePathForClass(Class<?> classs):

    /**
     * Returns the absolute path of the current directory in which the given
     * class
     * file is.
     * 
     * @param classs
     * @return The absolute path of the current directory in which the class
     *         file is.
     * @author GOXR3PLUS[StackOverFlow user] + bachden [StackOverFlow user]
     */
    public static final String getBasePathForClass(Class<?> classs) {

        // Local variables
        File file;
        String basePath = "";
        boolean failed = false;

        // Let's give a first try
        try {
            file = new File(classs.getProtectionDomain().getCodeSource().getLocation().toURI().getPath());

            if (file.isFile() || file.getPath().endsWith(".jar") || file.getPath().endsWith(".zip")) {
                basePath = file.getParent();
            } else {
                basePath = file.getPath();
            }
        } catch (URISyntaxException ex) {
            failed = true;
            Logger.getLogger(classs.getName()).log(Level.WARNING,
                    "Cannot firgue out base path for class with way (1): ", ex);
        }

        // The above failed?
        if (failed) {
            try {
                file = new File(classs.getClassLoader().getResource("").toURI().getPath());
                basePath = file.getAbsolutePath();

                // the below is for testing purposes...
                // starts with File.separator?
                // String l = local.replaceFirst("[" + File.separator +
                // "/\\\\]", "")
            } catch (URISyntaxException ex) {
                Logger.getLogger(classs.getName()).log(Level.WARNING,
                        "Cannot firgue out base path for class with way (2): ", ex);
            }
        }

        // fix to run inside eclipse
        if (basePath.endsWith(File.separator + "lib") || basePath.endsWith(File.separator + "bin")
                || basePath.endsWith("bin" + File.separator) || basePath.endsWith("lib" + File.separator)) {
            basePath = basePath.substring(0, basePath.length() - 4);
        }
        // fix to run inside netbeans
        if (basePath.endsWith(File.separator + "build" + File.separator + "classes")) {
            basePath = basePath.substring(0, basePath.length() - 14);
        }
        // end fix
        if (!basePath.endsWith(File.separator)) {
            basePath = basePath + File.separator;
        }
        return basePath;
    }

0

Этот код работал для меня:

private static String getJarPath() throws IOException, URISyntaxException {
    File f = new File(LicensingApp.class.getProtectionDomain().().getLocation().toURI());
    String jarPath = f.getCanonicalPath().toString();
    String jarDir = jarPath.substring( 0, jarPath.lastIndexOf( File.separator ));
    return jarDir;
  }

0

Этот код помог мне определить, выполняется ли программа внутри файла JAR или IDE:

private static boolean isRunningOverJar() {
    try {
        String pathJar = Application.class.getResource(Application.class.getSimpleName() + ".class").getFile();

        if (pathJar.toLowerCase().contains(".jar")) {
            return true;
        } else {
            return false;
        }
    } catch (Exception e) {
        return false;
    }
}

Если мне нужно получить полный путь к файлу JAR для Windows, я использую этот метод:

    private static String getPathJar() {
        try {
            final URI jarUriPath =
                    Application.class.getResource(Application.class.getSimpleName() + ".class").toURI();
            String jarStringPath = jarUriPath.toString().replace("jar:", "");
            String jarCleanPath  = Paths.get(new URI(jarStringPath)).toString();

            if (jarCleanPath.toLowerCase().contains(".jar")) {
                return jarCleanPath.substring(0, jarCleanPath.lastIndexOf(".jar") + 4);
            } else {
                return null;
            }
        } catch (Exception e) {
            log.error("Error getting JAR path.", e);
            return null;
        }
    }

Мой полный код, работающий с приложением Spring Boot с использованием CommandLineRunnerреализации, чтобы приложение всегда выполнялось в представлении консоли (Двойной щелчок по ошибке в имени файла JAR), я использую следующий код:

@SpringBootApplication
public class Application implements CommandLineRunner {
    public static void main(String[] args) throws IOException {
        Console console = System.console();

        if (console == null && !GraphicsEnvironment.isHeadless() && isRunningOverJar()) {
            Runtime.getRuntime().exec(new String[]{"cmd", "/c", "start", "cmd", "/k",
                    "java -jar \"" + getPathJar() + "\""});
        } else {
            SpringApplication.run(Application.class, args);
        }
    }

    @Override
    public void run(String... args) {
        /*
        Additional code here...
        */
    }

    private static boolean isRunningOverJar() {
        try {
            String pathJar = Application.class.getResource(Application.class.getSimpleName() + ".class").getFile();

            if (pathJar.toLowerCase().contains(".jar")) {
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            return false;
        }
    }

    private static String getPathJar() {
        try {
            final URI jarUriPath =
                    Application.class.getResource(Application.class.getSimpleName() + ".class").toURI();
            String jarStringPath = jarUriPath.toString().replace("jar:", "");
            String jarCleanPath  = Paths.get(new URI(jarStringPath)).toString();

            if (jarCleanPath.toLowerCase().contains(".jar")) {
                return jarCleanPath.substring(0, jarCleanPath.lastIndexOf(".jar") + 4);
            } else {
                return null;
            }
        } catch (Exception e) {
            return null;
        }
    }
}

-1

Я пишу на Java 7 и тестирую в Windows 7 со средой исполнения Oracle и Ubuntu со средой исполнения с открытым исходным кодом. Это прекрасно работает для этих систем:

Путь к родительскому каталогу любого работающего файла jar (при условии, что класс, вызывающий этот код, является прямым потомком самого архива jar):

try {
    fooDir = new File(this.getClass().getClassLoader().getResource("").toURI());
} catch (URISyntaxException e) {
    //may be sloppy, but don't really need anything here
}
fooDirPath = fooDir.toString(); // converts abstract (absolute) path to a String

Итак, путь к foo.jar будет:

fooPath = fooDirPath + File.separator + "foo.jar";

Опять же, это не было проверено ни на одном Mac или более старой Windows


-1

Этот getProtectionDomainподход иногда может не сработать, например, когда вам нужно найти jar для некоторых основных java-классов (например, в моем StringBuilderклассе case в IBM JDK), однако следующее работает без проблем:

public static void main(String[] args) {
    System.out.println(findSource(MyClass.class));
    // OR
    System.out.println(findSource(String.class));
}

public static String findSource(Class<?> clazz) {
    String resourceToSearch = '/' + clazz.getName().replace(".", "/") + ".class";
    java.net.URL location = clazz.getResource(resourceToSearch);
    String sourcePath = location.getPath();
    // Optional, Remove junk
    return sourcePath.replace("file:", "").replace("!" + resourceToSearch, "");
}

URL.getPath () не делает то, что вы думаете. Любые специальные символы будут закодированы в процентах.
VGR

-1

У меня есть другой способ получить расположение класса String.

URL path = Thread.currentThread().getContextClassLoader().getResource("");
Path p = Paths.get(path.toURI());
String location = p.toString();

Выходная строка будет иметь вид

C:\Users\Administrator\new Workspace\...

Пробелы и другие символы обрабатываются и в форме без file:/. Так будет проще в использовании.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.