Как получить путь к запущенному файлу JAR?
мой код работает внутри файла JAR, скажем foo.jar, и мне нужно знать, в коде,в какой папке работает foo.Джар есть.
Итак, если Foo.фляги в C:FOO
, Я хочу получить этот путь независимо от того, что мой текущий рабочий каталог.
29 ответов:
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
, есть два шага:
- преобразование
Class
доURL
- преобразование
URL
доFile
важно понимать оба шага, а не объединять их.
после
File
можно назватьgetParentFile
чтобы получить папку, если это необходимо.Шаг 1:
Class
доURL
как говорится в другие ответы, есть два основных способа найти
URL
, относящиеся кClass
.
URL url = Bar.class.getProtectionDomain().getCodeSource().getLocation();
URL url = Bar.class.getResource(Bar.class.getSimpleName() + ".class");
у обоих есть плюсы и минусы.
The
getProtectionDomain
подход дает базовое расположение класса (например, содержащий файл JAR). Однако, возможно, что политика безопасности среды выполнения Java будет бросатьSecurityException
при вызовеgetProtectionDomain()
, так что если ваше приложение должно работать в различных средах лучше всего тестировать во всех из них.The
getResource
подход дает полный путь ресурса URL класса, из которого вам нужно будет выполнить дополнительную манипуляцию строкой. Это может бытьfile:
путь, но это также может бытьjar:file:
или даже что-то более мерзкое, какbundleresource://346.fwk2106232034:4/foo/Bar.class
при выполнении в рамках OSGi. И наоборот,getProtectionDomain
подход правильно даетfile:
URL даже изнутри OSGi.обратите внимание, что оба
getResource("")
иgetResource(".")
не удалось в моих тестах, когда класс находился в файле JAR; оба вызова возвращали null. Поэтому я рекомендую вызов #2, показанный выше, поскольку он кажется более безопасным.Шаг 2:
URL
доFile
в любом случае, как только у вас есть
URL
, следующий шаг-преобразование вFile
. Это его собственный вызов; см. Kohsuke Кавагути пост об этом для полной информации, но вкратце, вы можете использовать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. * <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 Common библиотека:
вы также можете использовать:
CodeSource codeSource = YourMainClass.class.getProtectionDomain().getCodeSource(); File jarFile = new File(codeSource.getLocation().toURI().getPath()); String jarDir = jarFile.getParentFile().getPath();
Использовать Загрузчик Классов.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.
Я удивлен, что никто недавно не предложил использовать
Path
. Далее следует цитата:"ThePath
класс включает различные методы, которые можно использовать для получения информации о пути, доступа к элементам пути, преобразования пути в другие формы или извлечения частей пути"таким образом, хорошей альтернативой является получение
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(); }
У меня была та же проблема, и я решил ее таким образом:
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"));
выбранный ответ выше не работает, если вы запустите свой jar, нажав на него из среды рабочего стола Gnome (а не из какого-либо скрипта или терминала).
вместо этого, я люблю, что следующее решение работает везде:
try { return URLDecoder.decode(ClassLoader.getSystemClassLoader().getResource(".").getPath(), "UTF-8"); } catch (UnsupportedEncodingException e) { return ""; }
для получения пути запуска файла jar я изучил вышеуказанные решения и попробовал все методы, которые существуют некоторые различия друг с другом. Если этот код выполняется в Eclipse IDE, все они должны иметь возможность найти путь к файлу, включая указанный класс, и открыть или создать указанный файл с найденным путем.
но это сложно, когда вы запускаете запускаемый файл jar напрямую или через командную строку, он будет неудачным, так как путь к файлу jar получен из приведенного выше методы дадут внутренний путь в файле jar, то есть он всегда дает путь как
rsrc: project-name (возможно, я должен сказать, что это имя пакета основного файла класса-указанного класса)
Я не могу преобразовать rsrc:... путь к внешнему пути, то есть при запуске файла jar за пределами Eclipse IDE он не может получить путь к файлу jar.
единственный возможный способ получить путь к запуску файла jar вне Eclipse IDE-это
System.getProperty("java.class.path")
эта строка кода может возвращать живой путь (включая имя файла) запущенного файла jar (обратите внимание, что возвращаемый путь не является рабочим каталогом), поскольку документ java и некоторые люди сказали, что он вернет пути всех файлов классов в том же каталоге, но как мои тесты, Если в том же каталоге есть много файлов 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<name.length(); k++) { s += name.charAt(k); if (name.charAt(k) == ' ') k += 2; } // replace '/' with system separator char return s.replace('/', File.separatorChar); }
что касается сбоя с апплетами, вы обычно не будете иметь доступ к локальным файлам в любом случае. Я не знаю много о JWS, но для обработки локальных файлов может быть невозможно загрузить приложение.?
самое простое решение-передать путь в качестве аргумента при запуске jar.
Вы можете автоматизировать это с помощью shell-скрипт (.летучая мышь в окнах,. 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
Я пытался получить jar работает путь с помощью
String folder = MyClassName.class.getProtectionDomain().getCodeSource().getLocation().getPath();
c:\app>java-jar приложение.банку
запуск приложения jar с именем " application.jar", на Windows в папке"c:\app", значение строковой переменной "папка" было " \c:\app\application.банку " и у меня были проблемы с проверкой правильности пути
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.банку" и я заметил, что это работает.
что-то расстраивает, когда вы развиваетесь в 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"); }
не совсем уверен в других, но в моем случае он не работал с "Runnable jar" , и я получил его, исправив коды вместе с phchen2 answer и еще один из этой ссылки:Как получить путь к запущенному файлу 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
файл для запуска другого , который находится в том же каталоге.проблема в том, что когда вы начинаете его с
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 (предполагая, что класс, вызывающий этот код, является прямым потомком самого архива 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
Итак, путь фу.jar будет:
fooPath = fooDirPath + File.separator + "foo.jar";
опять же, это не было проверено на любом Mac или более старых Windows
The
getProtectionDomain
подход может не работать иногда, например, когда вам нужно найти jar для некоторых основных классов 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 path = Thread.currentThread().getContextClassLoader().getResource(""); Path p = Paths.get(path.toURI()); String location = p.toString();
выходная строка будет иметь вид
C:\Users\Administrator\new Workspace\...
пробелы и другие символы обрабатываются, и в форме без
file:/
. Так будет проще в использовании.
или вы можете передать бросить текущий поток следующим образом:
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/