Як отримати шлях запущеного файлу 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 Не дуже корисно!
Діно Фанселлу

Цікаво. Оригінальний код, в якому я це використовував, ніколи не був запущений у мурашника, тому для мене це не проблема.
Тіаго Чавес

2
@Dino Fancellu, я пережив саме те, що ви описали. Працює під час розробки, не спрацьовує, коли побудований для складування.
Бадді

Відповіді:


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

Замініть "MyClass" на ім'я вашого класу.

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


42
Цей toURI()крок важливий, щоб уникнути проблем зі спеціальними символами, включаючи пробіли та плюси. Правильна однолінійка: return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().toURI()); Використання URLDecoderне працює для багатьох спеціальних символів. Детальну інформацію див. У моїй відповіді нижче.
ctrueden

4
Примітка. Це повертає шлях, включаючи назву файлу jar
Buddy

8
Це не вказує на файл jar, а не на запущений каталог? Для цієї роботи вам доведеться зробити результат за результатом getParentFile ().
ФОО

1
Крім того, getProtectionDomainце недійсно, якщо ви отримуєте свій клас із зворотного треку:val strace = Thread.currentThread().getStackTrace; val path = strace(1).getClass.getProtectionDomain
bbarker

1
Використання цього методу до Java 8; розміщуючи цей метод у класі, який знаходиться у зовнішньому Jar, завантаженому через class-path, тоді шлях зовнішньої банки буде вказаний замість фактично запущеного 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для декодування спеціальних символів. Зокрема, такі символи +будуть помилково декодовані в пробіли. Детальну інформацію див. У моїй відповіді.
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, наступний крок перетвориться на a File. Це власний виклик; дивіться про це в блозі Kohsuke Kawaguchi , але коротко кажучи, ви можете користуватися до new File(url.toURI())тих пір, поки URL-адреса буде повністю сформована.

Нарешті, я б дуже не відштовхувався від використання URLDecoder. Деякі персонажі URL, :і , /зокрема, не є допустимими URL-кодованих символів. З URLDecoder Javadoc:

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

...

Є два можливі способи, за допомогою яких цей декодер міг би працювати з незаконними рядками. Він може або залишити незаконні символи в спокої, або він може кинути незаконний аргументЕксцепція. Який підхід бере декодер, залишається на реалізації.

На практиці, 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; найкраща відповідь на сьогоднішній день: він поверне шлях, використовуючи правильні позначення для ОС. (наприклад, \ для Windows).
Вірсавія

Щодо безпеки, я вважаю, що я виявив, що Java WebStart цього не дозволяє.
Thorbjørn Ravn Andersen

55

Ви також можете використовувати:

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

3
Це працює для мене краще, бо це дає шлях Яру, а не класу!
T30

Працював і для мене. Поєднайтеся з відповіддю Фаба, і це стане краще!
Даніельсон Алвеш Хуніор

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 щодо формату URL-адреси jar.


Мій файл 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 jar.
Джон Скіт

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 (у тому самому місці банку):

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для декодування спеціальних символів. Зокрема, такі символи +будуть помилково декодовані в пробіли. Детальну інформацію див. У моїй відповіді.
ctrueden

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

URLDecoder, незважаючи на свою назву, призначений для декодування URL-адрес і імен параметрів форми та значень, а не URL-адрес.
Маркіз Лорн

6

Щоб отримати шлях запуску jar-файлу, я вивчив вищезазначені рішення та спробував усі методи, які існують у різниці між собою. Якщо цей код працює в Eclipse IDE, всі вони повинні мати можливість знайти шлях до файлу, включаючи вказаний клас, та відкрити або створити вказаний файл із знайденим шляхом.

Але це складно, коли запустити файл jar jar безпосередньо або через командний рядок, це буде невдалим, оскільки шлях файлу jar, отриманий з вищевказаних методів, дасть внутрішній шлях у файлі jar, тобто він завжди дає шлях як

rsrc: ім'я проекту (можливо, я повинен сказати, що це ім'я пакету файлу основного класу - вказаний клас)

Я не можу конвертувати rsrc: ... шлях у зовнішній шлях, тобто коли запустити файл jar поза ID Eclipse, він не може отримати шлях файлу jar.

Єдиний можливий спосіб отримати шлях запуску файлу jar поза Eclipse IDE

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

цей рядок коду може повернути живий шлях (включаючи ім'я файлу) запущеного файлу jar (зверніть увагу, що шлях повернення не є робочим каталогом), оскільки документ java та деякі люди сказали, що він поверне шляхи всіх файлів класу в тому самому каталозі, але як і мої тести, якщо в одному каталозі містяться багато файлів jar, він повертає лише шлях запущеної jar (з приводу випуску декількох шляхів насправді це сталося в Eclipse).


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

Я підтверджую, я спробував інші рішення, але ніколи не отримав назву файлу jar. Це працює дуже просто! спасибі - +1
guillaume girod-vitouchkina

5

Інші відповіді, схоже, вказують на джерело коду, який є файлом Jar, який не є каталогом.

Використовуйте

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

Це може бути каталог, якщо ви завантажуєте свої класи з файлової системи замість файлу JAR, наприклад, під час налагодження.
Маркіз Лорн

4

обраний вище відповідь не працює, якщо ви запускаєте свою банку, натиснувши на неї з середовища робочого столу Gnome (не з будь-якого сценарію чи терміналу).

Натомість мені подобається, що таке рішення працює скрізь:

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

2
Ви спробували це в аплеті чи додатку. запущений за допомогою Java Web Start? Я розумію, що в обох ситуаціях воно не вдасться (навіть якщо програмі довіряти).
Ендрю Томпсон

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

Обережно: не рекомендується використовувати URLDecoderдля декодування спеціальних символів. Зокрема, такі символи +будуть помилково декодовані в пробіли. Детальну інформацію див. У моїй відповіді.
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 " значення змінної String "папка" було " \ 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

Найпростіше рішення - пройти шлях як аргумент під час запуску jar.

Ви можете автоматизувати це за допомогою сценарію оболонки (.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каталог, який є чудовим, але коли ви збираєте його в банку, шлях включає ту /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

Спробували декілька рішень там, але жодне не дало правильних результатів для (мабуть, спеціального) випадку, коли запущена банка експортується із "Упаковка зовнішніх бібліотек" у 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;
    }
}

Якщо мені потрібно отримати повний шлях Windows до файлу JAR, я використовую цей метод:

    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Підхід може не працювати іноді , наприклад , коли ви повинні знайти баночку для деяких з основних класів Java (наприклад , в моєму випадку StringBuilderклас в 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.