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

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

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

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

Замените «MyClass» на имя вашего classа

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

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

 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 дает базовое расположение classа (например, содержащий JAR-файл). Тем не менее, вполне возможно, что политика безопасности среды выполнения Java будет бросать SecurityException при вызове getProtectionDomain() , поэтому, если ваше приложение должно работать в различных средах, лучше всего протестировать их во всех них.

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

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

Шаг 2: URL File

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

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

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

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

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

Рабочий код

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

 /** * Gets the base location of the given class. * 

* If the class is directly on the file system (eg, * "/path/to/my/package/MyClass.class") then it will return the base directory * (eg, "file:/path/to"). *

*

* If the class is within a JAR file (eg, * "/path/to/my-jar.jar!/my/package/MyClass.class") then it will return the * path to the JAR (eg, "file:/path/to/my-jar.jar"). *

* * @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}. *

* 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. *

* * @param url The URL to convert. * @return A file path suitable for use with eg {@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 eg {@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 Common :

  • org.scijava.util.ClassUtils
  • org.scijava.util.FileUtils .

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

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

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

Например:

 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.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  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 

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

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

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

Самое простое решение – передать путь в качестве аргумента при запуске банки.

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

 java -jar my-jar.jar . 

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

ОБНОВИТЬ

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

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

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

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

Мне пришлось много возиться до того, как я наконец нашел рабочее (и короткое) решение.
Возможно, что 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

Я попытался запустить путь работы банки, используя

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

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

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

 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"); 

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

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

Игнорируйте ответ резервного помощника, он может выглядеть нормально, но имеет несколько проблем:

здесь оба должны быть +1 не -1:

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

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

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

Для белых пробелов лучше, чем этот цикл.

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

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

Путь к родительскому каталогу любого запущенного файла jar (если class, вызывающий этот код, является прямым дочерним элементом самого архива 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

Подход getProtectionDomain может не работать иногда, например, когда вам нужно найти банку для некоторых основных classов Java (например, в моем случае class 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, ""); } 

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

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

Строка вывода будет иметь форму

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

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

Или вы можете передать текущий stream таким образом:

 String myPath = Thread.currentThread().getContextClassLoader().getResource("filename").getPath(); 

Этот один лайнер работает для папок, содержащих пробелы или специальные символы (например, ç или õ). Исходный вопрос задает абсолютный путь (рабочий каталог) без самого файла JAR. Протестировано здесь с Java7 на Windows7:

 String workingDir = System.getProperty("user.dir"); 

Ссылка: http://www.mkyong.com/java/how-to-get-the-current-working-directory-in-java/

  • Конкатенация строк в Less
  • Как определить относительный путь в java (Windows)
  • Как объединить пути в Java?
  • Как я могу обновить установку Python по умолчанию или исправить мой $ PATH на Mac OS X 10.6.7?
  • Найти имя файла из полного пути к файлу
  • Возможные проблемы с добавлением / usr / local / bin к корневому пути?
  • Как изменить папку запуска Jupyter
  • Как получить рабочий путь приложения wcf?
  • Перемещение файла app.config на пользовательский путь
  • Передача двух параметров команды с использованием привязки WPF
  • Что такое PATH и другие переменные среды, и как я могу их установить или использовать?
  • Interesting Posts

    Возrotation ссылки const на объект вместо копии

    запросить бобовые бобы весенним тестированием

    Как найти самый низкий общий предк двух узлов в любом двоичном дереве?

    Убить слишком много для драйверов ATI?

    Убедитесь, что неуправляемая DLL 32-разрядная или 64-разрядная?

    Как генерировать распределенные данные, средние, SD, перекос и эксцесс в R?

    Почему cout печатает массивы char по-разному от других массивов?

    boolean против BitSet: что более эффективно?

    В Windows 7 есть ли строка командной строки, которая может запускать cmd в качестве администратора?

    Как обмениваться памятью между процессом fork ()?

    Почему мой компьютер не работает на полной скорости?

    Эмулировать split () с dplyr group_by: вернуть список кадров данных

    Метод Image.FromStream () возвращает исключение Invalid Argument

    xcopy файл, переименовать, подавить сообщение «Does xxx указать имя файла …»

    Android WIFI Как обнаружить, когда доступно специальное WIFI-соединение

    Давайте будем гением компьютера.