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

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

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

37 ответов

Решение
return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation()
    .toURI()).getPath();

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

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

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

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

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

Чтобы получить 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:

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

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

Используйте 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.

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

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

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

Единственное решение, которое работает для меня на 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();
}

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

new File(".").getCanonicalPath()

Сбор входных данных из других ответов тоже прост:

String localPath=new File(getClass().getProtectionDomain().getCodeSource().getLocation().toURI()).getParentFile().getPath()+"\\"; 

Оба вернут строку в этом формате:

"C:\Users\User\Desktop\Folder\"

В простой и лаконичной строке.

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

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

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

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

используя относительную "папку" вне файла.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"));

Для получения пути запуска 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).

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

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

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

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

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

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

Для пути к файлу jar:

      String jarPath = File(MyClass.class.getProtectionDomain().getCodeSource().getLocation()
    .toURI()).getPath();

Для получения пути к каталогу этого файла jar:

      String dirPath = new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation()
                        .toURI()).getParent();

Результаты двух строк выше выглядят так:

/home/user/MyPrograms/myapp/myjar.jar (для пути jar)

/home/user/MyPrograms/myapp (для пути к каталогу)

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

URL jarLocationUrl = MyClass.class.getProtectionDomain().getCodeSource().getLocation();
String jarLocation = new File(jarLocationUrl.toString()).getParent();
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

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

  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, но для обработки локальных файлов может быть невозможно загрузить приложение.

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

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", и я заметил, что он работает.

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

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

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

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

java -jar my-jar.jar .

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

ОБНОВИТЬ

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

Опробовали несколько решений, но ни одно из них не дало правильных результатов для (вероятно, особого) случая, когда исполняемый файл 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);

Попробуй это:

String path = new File("").getAbsolutePath();

Этот код помог мне определить, выполняется ли программа внутри файла 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;
        }
    }
}

Что разочаровывает, так это то, что когда вы разрабатываете в 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");
}

Не совсем уверен насчет других, но в моем случае это не сработало с "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");

Вышеупомянутые методы не работали для меня в моей среде Spring, поскольку Spring затеняет фактические классы в пакет с именем BOOT-INF, таким образом, не фактическое расположение запущенного файла. Я нашел другой способ получить текущий файл через Permissions объект, предоставленный работающему файлу:

      
public static Path getEnclosingDirectory() {
    return Paths.get(FileUtils.class.getProtectionDomain().getPermissions()
            .elements().nextElement().getName()).getParent();
}

Укажите, что это проверено только в 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;
    }

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

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;
  }

Я пишу на 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, а не -1:

name = name.substring(name.lastIndexOf(':')-1, name.lastIndexOf('/')+1).replace('%', ' ');

Очень опасно, потому что не сразу видно, если в пути нет пробелов, но замена только "%" оставит вас с кучей 20 в каждом пробеле:

name = name.substring(name.lastIndexOf(':')-1, name.lastIndexOf('/')+1).replace('%', ' ');

Есть лучшие способы, чем этот цикл для пробелов.

Также это вызовет проблемы во время отладки.

Другие вопросы по тегам