Мій код працює всередині файлу JAR, скажімо foo.jar , і мені потрібно знати, в коді, в якій папці працює запущений foo.jar .
Отже, якщо foo.jar є C:\FOO\
, я хочу пройти цей шлях, незалежно від того, який у мене зараз робочий каталог.
Мій код працює всередині файлу JAR, скажімо foo.jar , і мені потрібно знати, в коді, в якій папці працює запущений foo.jar .
Отже, якщо foo.jar є C:\FOO\
, я хочу пройти цей шлях, незалежно від того, який у мене зараз робочий каталог.
Відповіді:
return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation()
.toURI()).getPath();
Замініть "MyClass" на ім'я вашого класу.
Очевидно, це зробить дивні речі, якщо ваш клас завантажено з нефайлового місця.
toURI()
крок важливий, щоб уникнути проблем зі спеціальними символами, включаючи пробіли та плюси. Правильна однолінійка: return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().toURI());
Використання URLDecoder
не працює для багатьох спеціальних символів. Детальну інформацію див. У моїй відповіді нижче.
getProtectionDomain
це недійсно, якщо ви отримуєте свій клас із зворотного треку:val strace = Thread.currentThread().getStackTrace; val path = strace(1).getClass.getProtectionDomain
Найкраще рішення для мене:
String path = Test.class.getProtectionDomain().getCodeSource().getLocation().getPath();
String decodedPath = URLDecoder.decode(path, "UTF-8");
Це повинно вирішити проблему з пробілами та спеціальними символами.
URLDecoder.decode(ClassLoader.getSystemClassLoader().getResource(".").getPath(), "UTF-8");
) в Linux. Однак я не пробував Windows.
URLDecoder
для декодування спеціальних символів. Зокрема, такі символи +
будуть помилково декодовані в пробіли. Детальну інформацію див. У моїй відповіді.
Для отримання File
заданої дати Class
є два етапи:
Class
на аURL
URL
на аFile
Важливо розуміти обидва кроки, а не плутати їх.
Після того File
, як ви getParentFile
отримаєте , ви можете зателефонувати, щоб отримати папку, що містить, якщо це те, що вам потрібно.
Class
доURL
Як обговорювалося в інших відповідях, існує два основні способи знайти URL
відповідне питання Class
.
URL url = Bar.class.getProtectionDomain().getCodeSource().getLocation();
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, показаний вище, натомість, як це здається більш безпечним.
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);
}
Ви також можете використовувати:
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 щодо формату URL-адреси jar.
NPE
тому що ви не відповіли на запитання, яке було задано (шлях до реєстру JAR був заданий, і ви відповіли на абсолютно інше питання: шлях до класу). 2. Як вказували інші, і у мене з'явився той самий випуск, він не працює для аплетів. 3. Повертається шлях не канонічного подання шляху взагалі: jar:file:/listener/build/libs/listener-1.0.0-all.jar!/shared/Test.class
.
Я здивований, побачивши, що жоден нещодавно не пропонував використовувати 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"));
URLDecoder
для декодування спеціальних символів. Зокрема, такі символи +
будуть помилково декодовані в пробіли. Детальну інформацію див. У моїй відповіді.
URLDecoder
, незважаючи на свою назву, призначений для декодування URL-адрес і імен параметрів форми та значень, а не URL-адрес.
Щоб отримати шлях запуску 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, який не є каталогом.
Використовуйте
return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()).getParentFile();
обраний вище відповідь не працює, якщо ви запускаєте свою банку, натиснувши на неї з середовища робочого столу Gnome (не з будь-якого сценарію чи терміналу).
Натомість мені подобається, що таке рішення працює скрізь:
try {
return URLDecoder.decode(ClassLoader.getSystemClassLoader().getResource(".").getPath(), "UTF-8");
} catch (UnsupportedEncodingException e) {
return "";
}
URLDecoder
для декодування спеціальних символів. Зокрема, такі символи +
будуть помилково декодовані в пробіли. Детальну інформацію див. У моїй відповіді.
NullPointerException
NPE
якщо в JAR ресурсів немає.
Насправді тут краща версія - стара не вдалася, якщо в назві папки було пробіл.
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 " значення змінної 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 ", і я помітив, що він працює.
Найпростіше рішення - пройти шлях як аргумент під час запуску jar.
Ви можете автоматизувати це за допомогою сценарію оболонки (.bat в Windows, .sh де завгодно):
java -jar my-jar.jar .
Я .
передавав поточний робочий каталог.
ОНОВЛЕННЯ
Ви можете вставити файл jar в підкаталог, щоб користувачі випадково не клацнули по ньому. Ваш код також повинен перевірити, щоб переконатися, що аргументи командного рядка надані, та надати гарне повідомлення про помилку, якщо аргументи відсутні.
Мені довелося багато возитися, перш ніж я нарешті знайшов робоче (і коротке) рішення.
Цілком можливо, що jarLocation
поставляється з префіксом типу, file:\
або jar:file\
, який можна видалити за допомогою String#substring()
.
URL jarLocationUrl = MyClass.class.getProtectionDomain().getCodeSource().getLocation();
String jarLocation = new File(jarLocationUrl.toString()).getParent();
String path = getClass().getResource("").getPath();
Шлях завжди посилається на ресурс у файлі jar.
String path = new File(getClass().getResource("").getPath()).getParentFile().getParent(); File jarDir = new File(path.substring(5));
getResource("")
і getResource(".")
не вдалося в моїх тестах, коли клас знаходився у файлі JAR; обидві виклики повернулися до нуля
NullPointerException
.
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
Щось засмучує те, що коли ви розвиваєтеся в 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 відповіді та іншим за цим посиланням: Як отримати шлях запущеного файлу 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");
Спробували декілька рішень там, але жодне не дало правильних результатів для (мабуть, спеціального) випадку, коли запущена банка експортується із "Упаковка зовнішніх бібліотек" у 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);
Цей метод, викликаний з коду в архіві, повертає папку, де знаходиться файл .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;
}
Цей код працював на мене, щоб визначити, чи виконується програма всередині файлу 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;
}
}
}
Я пишу в 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
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, "");
}
У мене є ще один спосіб отримати місце String у класі.
URL path = Thread.currentThread().getContextClassLoader().getResource("");
Path p = Paths.get(path.toURI());
String location = p.toString();
Вихідна рядок буде мати вигляд
C:\Users\Administrator\new Workspace\...
Пробіли та інші символи обробляються, причому у формі без file:/
. Так буде простіше у використанні.