To obtain the File
for a given Class
, there are two steps:
- Convert the
Class
to aURL
- Convert the
URL
to aFile
It is important to understand both steps, and not conflate them.
Once you have the File
, you can call getParentFile
to get the containing folder, if that is what you need.
Step 1: Class
to URL
As discussed in other answers, there are two major ways to find a URL
relevant to a Class
.
-
URL url = Bar.class.getProtectionDomain().getCodeSource().getLocation();
-
URL url = Bar.class.getResource(Bar.class.getSimpleName() + ".class");
Both have pros and cons.
The getProtectionDomain
approach yields the base location of the class (e.g., the containing JAR file). However, it is possible that the Java runtime’s security policy will throw SecurityException
when calling getProtectionDomain()
, so if your application needs to run in a variety of environments, it is best to test in all of them.
The getResource
approach yields the full URL resource path of the class, from which you will need to perform additional string manipulation. It may be a file:
path, but it could also be jar:file:
or even something nastier like bundleresource://346.fwk2106232034:4/foo/Bar.class
when executing within an OSGi framework. Conversely, the getProtectionDomain
approach correctly yields a file:
URL even from within OSGi.
Note that both getResource("")
and getResource(".")
failed in my tests, when the class resided within a JAR file; both invocations returned null. So I recommend the #2 invocation shown above instead, as it seems safer.
Step 2: URL
to File
Either way, once you have a URL
, the next step is convert to a File
. This is its own challenge; see Kohsuke Kawaguchi’s blog post about it for full details, but in short, you can use new File(url.toURI())
as long as the URL is completely well-formed.
Lastly, I would highly discourage using URLDecoder
. Some characters of the URL, :
and /
in particular, are not valid URL-encoded characters. From the URLDecoder Javadoc:
It is assumed that all characters in the encoded string are one of the following: “a” through “z”, “A” through “Z”, “0” through “9”, and “-“, “_”, “.”, and “*”. The character “%” is allowed but is interpreted as the start of a special escaped sequence.
…
There are two possible ways in which this decoder could deal with illegal strings. It could either leave illegal characters alone or it could throw an IllegalArgumentException. Which approach the decoder takes is left to the implementation.
In practice, URLDecoder
generally does not throw IllegalArgumentException
as threatened above. And if your file path has spaces encoded as %20
, this approach may appear to work. However, if your file path has other non-alphameric characters such as +
you will have problems with URLDecoder
mangling your file path.
Working code
To achieve these steps, you might have methods like the following:
/**
* 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);
}
You can find these methods in the SciJava Common library:
- org.scijava.util.ClassUtils
- org.scijava.util.FileUtils.
How does one obtain the location of the executable of the currently running JVM during runtime? I would like to instantiate another JVM as a subprocess using the ProcessBuilder class.
I am aware that there is the java.home
System property, but this doesn’t specify the location of the JVM executable. I understand I could do something like this to get the path:
System.getProperties().getProperty("java.home") + File.pathSeparator + "bin" + File.pathSeparator + "java"
This code isn’t platform independent, because the Windows executable’s name is java.exe
, not java
. Is there a way to get the path of the JVM executable that takes the platform’s idiosyncrasies into account?
asked Aug 2, 2010 at 22:53
5
You could always just use os.name to check if the user is running Windows or not. That’ll work on OS X, Linux and Windows at
String jvm_location;
if (System.getProperty("os.name").startsWith("Win")) {
jvm_location = System.getProperties().getProperty("java.home") + File.separator + "bin" + File.separator + "java.exe";
} else {
jvm_location = System.getProperties().getProperty("java.home") + File.separator + "bin" + File.separator + "java";
}
cello
5,3063 gold badges22 silver badges28 bronze badges
answered Jun 18, 2014 at 21:07
XenxierXenxier
4214 silver badges7 bronze badges
0
Following code obtains path to current java
executable by using ProcessHandle.Info
of current ProcessHandle
.
Result is wrapped in Optional
since the access to command info may be restricted by operating system permissions.
String javaExecutablePath = ProcessHandle.current()
.info()
.command()
.orElseThrow();
answered May 18, 2020 at 1:13
czernyczerny
14.7k14 gold badges68 silver badges94 bronze badges
3
This thread has an interesting discussion of the issue covering several platforms:
Finding current executable’s path without /proc/self/exe
Given that discussion, it should be possible, if you really needed it, to write some JNI wrapper that #ifdef’s the current platform and makes the proper native call.
If you’re only on Linux the ‘/proc/self/exe’ is a symbolic link to the actual executable being run. This has the advantage of not relying on any environment variables (i.e. PATH or JAVA_HOME). But as I said, it’s definitely not platform independent.
answered May 13, 2013 at 18:53
pedorropedorro
2,99924 silver badges24 bronze badges
Yes, there is a way to get the path of the JVM executable (if it exists). Include it in the configuration of the application. There are lots of ways to do that: Command line argument — java myApp.Main /path/to/Java; Properties — java -Dpath.to.java=/path/to/java; etc.
If you want true platform independence, then your whole scheme is flawed because the existence of a JVM executable is not guaranteed. I could imagine a JVM with no need for a java executable.
If you want 99.99% platform independence, then I think you have the tools needed.
answered Aug 3, 2010 at 2:36
emoryemory
10.7k2 gold badges29 silver badges58 bronze badges
2
You are trying to fork the entire JVM.
- That is extremely inefficient, mainly because of the heaviness of yet another java process. If your heavily doing this, then your program is going to be really slow
- Threads exist for this very reason
But if you really must, you can try just executing java -arguments
directly, since most standard java installations put java on the cli path.
answered Aug 3, 2010 at 2:26
TheLQTheLQ
14.8k14 gold badges69 silver badges107 bronze badges
3
Уровень сложности
Средний
Время на прочтение
4 мин
Количество просмотров 3.2K
Постановка цели
Как я уже писала в своей предыдущей статье, недавно, после двухлетнего обучения (обещали 12 месяцев, но жизненные и геополитические обстоятельства внесли свои коррективы в сроки получения дополнительного образования), я стала java-разработчиком.
Завершение обучения требовало написания выпускного проекта, которым я, изрядно поразмыслив, решила «убить сразу несколько зайцев»:
-
проект должен быть написан мной самостоятельно (без команды),
-
быть законченным и полноценным с точки зрения «бэка и фронта»,
-
функционал проекта должен нести какую-то информативную пользу,
-
проект станет подарком на день рождения.
Вспомнив все, чему меня “пытались научить”, я решила, что за 1,5 месяца, отведенных на выпускную работу (с учетом загруженности по основному месту своей занятости), я вполне самостоятельно справлюсь с написанием оконного приложения для рабочего стола по предоставлению пользователю текущих и прогнозных значений погоды. Оболочку приложения решила выполнить на JavaFX, а для получения данных о погоде использовать JSON.
Когда я выслала преподавателю техническое задание с характеристиками проекта, он, восседая на удобном кресле где-то в пригороде германского города Мюнхен, меня, великовозрастную студентку из Санкт-Петербурга, «обрадовал и окрылил» тем, что знания по JavaFX в реальной жизни мне не пригодятся, и я рискую впустую потратить время…
Ну что же, такая откровенность на завершающей стадии обучения, конечно, похвальна. Осознав, что целый курс, посвященный разработке приложения на JavaFX, получается, еще год назад был пустой тратой времени, я решила не отступаться и попробовать реализовать задуманное.
Процесс и трудности, с которыми пришлось столкнуться
Не особо вдумываясь в тонкости платформы JavaFX и ее представлении в выпусках Java-8, я решила писать приложение на JDK-1.8 в среде разработки IntelliJ IDEA Community Edition, используя maven.
Начиная создавать проект стандартным путем и пытаясь упростить себе жизнь, я выбрала настройки, как показаны на скриншоте:
и, нажав на кнопку «Next», получила неожиданное для себя сообщение:
Да-да, я не знала той тонкости, что JavaFX, представленный как часть выпуска Java-8, был удален из JDK и перенесен в отдельный модуль в Java-11.
Ну что же, начав все сначала, я выбрала JDK-11.0.2, и у меня чудесным образом создался проект с необходимыми классами и ресурсными файлами, со всеми нужными зависимостями и способами сборки, автоматически прописанными в pom.xml файле:
Чтобы проверить, действительно ли работает минимальный функционал будущего приложения, я запустила класс HelloApplication.java и получила результат, свидетельствующий, что все в порядке:
Далее была длительная полуторамесячная работа над проектом, в процессе которой:
-
я внесла изменения в базовый код, сформированный IntelliJ IDEA автоматически,
-
создала сцены с помощью JavaFX Scene Builder 2.0,
-
установила получение информации по JSON,
-
и прочее, прочее, прочее… пока в среде разработки все не начало запускаться, открываться и отображаться так, как мне бы хотелось.
С финальной версией проекта и демонстрацией его возможностей можно ознакомиться на GitHub.
Теоретически, проект готов, образовательная цель достигнута, его можно сдать как выпускную работу и выдохнуть.
Но, не забываем, программа должна была стать подарком на день рождения. У именинника не установлена Java, чтобы запустить jar-файл проекта и наслаждаться результатом работы приложения. Значит, нужно собрать проект в исполняемый .exe файл, который будет запускаться на любом устройстве с установленной системой Windows.
«Ерунда какая!» – подумала я, – «У меня же IntelliJ IDEA, она все сама соберет и подскажет, в случае чего».
Захожу в File -> Project Settings -> Artifacts -> JavaFx application -> From Module ‘имя модуля’
Добавляю к артефакту всю библиотеку зависимостей, что у меня есть в проекте (краем глаза вижу красные символы, которые должны бы вызвать тревогу и заставить меня призадуматься, но я так увлечена процессом, что не придаю им значения):
Заполняю сведения об основном классе, который запускает приложение (поле Application class):
В той же вкладке указываю значение «all» в поле Native bundle и применяю настройки:
После вхожу в режим Build -> Build Artifacts, выбираю только что созданный артефакт и… получаю сообщение, что используемая версия JDK не способна собрать мой проект в необходимый пакет:
Начитавшись всего, чего только возможно, во всемирной паутине, я решаюсь на эксперимент:
1. Заменила в pom.xml файле версию Java 11 на 8, обновилась:
2. В File -> Project Structure -> Project указала корректную версию используемой SDK:
3. Закомментировала (можно удалить) файл module-info.java, сформированный Java-11 автоматически при создании проекта:
4. Проверила, запускается ли приложение до сборки:
5. Описанными выше способами снова создала и собрала артефакт. Но! – опять получила ошибку:
6. После непродолжительных поисков причины я поняла, что на ноутбуке, на котором написана моя программа, собрать ее в исполняемый .exe файл у меня пока не получится, т.к. в наименовании пути к директории не должно быть ни кириллицы, ни специальных символов:
И изменение имени учетной записи Windows вручную не приведет к изменению имени пользовательской папки.
7. Не рискнув «копаться в мозгах» установленной на ноутбуке операционной системы, я воспользовалась стационарным компьютером, не имеющим в наименовании директорий кириллицу, и спокойно собрала проект.
Запускаемый .exe файл располагается в папке outartifactsназвание артефактаbundlesназвание проекта:
Вместо заключения
При кажущейся простоте создания приложения на JavaFX (особенно с помощью JavaFX Scene Builder 2.0 и бесплатных видео-уроков на различных ресурсах), написание функционала программы – это только половина пути. Программа должна работать, жить своей жизнью самостоятельно, без привязки к среде разработки. И, как показывает мой личный опыт, при сборке проекта и выпуске его в «большой мир» приходится преодолевать немало терний.
Надеюсь, что моя статья поможет кому-нибудь избежать ошибок, найти ответы на вопросы или просто сразу пойти правильным путем (например, создавать обычный maven-проект на Java-8, вручную прописывая в pom.xml зависимости и способ сборки, и всегда указывать на латинице имена учетных записей, директорий в своей операционной системе).
Здравствуйте, сегодня попробуем написать простую программу на языке программирования Java, сохраним её в формате “exe”, после чего наша программа будет запускаться на любом компьютере с ОС Windows.
Скачать исходники для статьи можно ниже
Создадим простенькую программку в формате EXE, которая попросит нас ввести для неё два числа и выведит для нас результат в виде этих же чисел, но только увеличенных на 1.
Скачать готовую программу можно по следующей ссылке – “yadi.sk/d/Kf5A7CQYrQTfE”
Приступим к созданию данной программы:
1. Устанавливаем бесплатную программу Eclipse
Официальный сайт “eclipse.org/downloads/”
Скачиваем “Eclipse IDE for Java EE Developers”:
Здесь есть Eclipse как для 32 разрядной операционной системы, так и для 64 разрядной системы.
Как узнать какая у вас система?
Наведите правой клавишей мыши на ярлык “Мой компьютер”, выберите пункт “Свойства”:
Скачается zip-архив, если вы попробуете распаковать его встроенным в windows архиватором, то здесь могут возникнуть проблемы – процесс может затянуться на длительное время или вовсе с ошибкой. Лучше всего это сделать с помощью программ WinRAR или 7-zip.
2. Далее устанавливаем Комплект Разработчика Приложений на языке Java – Java Software Development Kit (Java SDK или JDK).
Скачать его (JDK) можно с официального сайта – “oracle.com/technetwork/java/javase/downloads/index.html”
Здесь вам также предложат скачать JDK для различных операционных систем, замечу, что 32 разрядной для windows – вы не найдете, JDK для Windows x32 – можно скачать здесь – Скачать JDK для windows x32 и как его установить
После установки JDK стоит проверить его работу – для этого – откройте командную строку снова (Пуск > Выполнить. В текстовом поле наберите «cmd» и нажмите «Enter».). Наберите команду «javac» (без кавычек, конечно).
Если у вас выводится сообщение как на скриншоте выше, то все нормально.
Если нет и показывается следующее сообщение:
То прочтите мою статью по следующей ссылке – Скачать JDK для windows x32 и как его установить.
3. Скачайте бесплатную программу launch4j.
Она предназначена для компиляции всех ваших java файлов в один исполняемый “exe” файл.
Вы можете скачать launch4j с сайта “sourceforge.net/projects/launch4j/files/launch4j-3/3.1.0-beta1/”
или по следующей ссылке:
“https://mnogoblog.ru/wp-content/uploads/2016/04/launch4j-3.8-win32.zip”
4. Теперь осталось написать простенькую программу на языке программирования JAVA в программе Eclipse.
Для изучения языка программирования Java есть хороший youtube канал – ZhirniToni – “youtube.com/user/ZhirniToni” и в нем есть плейлист “Java для Чайников”, так вот на основе уроков 7, 8 и 14:
Урок 7: “youtu.be/lBE20G5l0YU”
Урок 8: “youtu.be/L-Ivs-ZfbT8”
Урок 14: “youtu.be/XUJsJ_loOkE”
Конечно же, лучше посмотреть все обучающие видео хотя бы с 1 по 14 урок, чтобы лучше разбираться в коде программы.
———————-
Благодаря урокам 7 и 8 у меня в программе Eclipse получилось 2 файла: main.java и reader.java.
Код файла main.java:
package ru.proekt; import javax.swing.JFrame; public class main { public static void main(String[] args) { reader r = new reader("Моя программа"); r.setVisible (true); r.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); r.setSize(300, 200); } }
Код файла reader.java:
package ru.proekt; import javax.swing.*; import java.awt.*; import java.awt.event.*; public class reader extends JFrame { JButton b1, b2; JLabel l1, l2, l3, l4; JTextField t1, t2; int i, k; String a, b; eHandler handler = new eHandler(); public reader(String s) { super(s); setLayout(new FlowLayout()); b1=new JButton ("Очистить"); b2=new JButton ("Посчитать"); l1=new JLabel ("Введите первое число:"); l2=new JLabel ("Введите второе число:"); l3=new JLabel (""); l4=new JLabel (""); t1=new JTextField (10); t2=new JTextField (10); add(b1); add(b2); add(l1); add(l2); add(l3); add(l4); add(t1); add(t2); b2.addActionListener(handler); b1.addActionListener(handler); } public class eHandler implements ActionListener { public void actionPerformed(ActionEvent e) { try { if (e.getSource()==b2){ i=Integer.parseInt(t1.getText()); k=Integer.parseInt(t2.getText()); i++; k++; a = "Ваше первое число теперь равно: " + i; b = "Ваше второе число теперь равно: " + k; l3.setText(a); l4.setText(b); } if (e.getSource()==b1){ t1.setText(null); t2.setText(null); l3.setText(""); l4.setText(""); } }catch (Exception ex){JOptionPane.showMessageDialog(null, "Введите в поле число.");} } } }
———————-
После того как вы напишите программу на Eclips сохранить её аналогично уроку 14, только тип файла нужно выбрать “Runnable JAR file”, а именно, вот так:
– кликаем мышкой на проект, который хотим сохранить:
– далее щелкните правой кнопкой мыши по вашему проекту и нажмите “Export” (Экспорт).
– откройте папку “Java” и дважды нажмите опцию “Runnable JAR file” (исполняемый архив JAR).
– Первое, что вы должны сделать, это выбрать главный класс (класс с основным методом) из выпадающего меню под “Launch configuration” (конфигурации запуска).
Во-вторых, выберите “Export destination” (Место экспорта) с помощью кнопки “Browse…” (Обзор) или вручную, вводя месторасположение.
И в-третьих, обеспечьте выбор переключателя “Extract required libraries into generated JAR”(Извлечь необходимые библиотеки в созданные JAR) “.
И, наконец, нажмите кнопку “Finish” (Готово).
———————-
Выкладываю вам JAR файл, который у меня получился – скачать JAR файл можно по следующей ссылке – “yadi.sk/d/o0Q8iWE7rQTZp”
5. А далее сохраним нашу программу на JAVA с помощью программы launch4j в exe файл.
Запускаем launch4j.
В первом текстовом поле введите или выберите с помощью просмотра место, где исполняемый файл хотите сохранить. Убедитесь, что имя файла имеет “.exe” в конце названия!
Во втором текстовом поле введите или выберите с помощью просмотра файл .jar, ранее экспортированного из Eclipse.
В четвертом текстовом поле с надписью “Icon:” можно выбрать иконку для программы, однако, это не является обязательным, и если его оставить пустым, ваша ОС вернется к своему значку по умолчанию исполняемого файла.
На вкладке “JRE” в верхнем меню выберите “Min JRE version” и введите “1.4.0”. Это гарантирует, что пользователи имеют нужную версию Java для использования вашей программы. Вы можете изменить это, но 1.4.0 является безопасной версией.
Нажмите кнопку передач под названием “Build wrapper” в верхней части экрана.
Программа вместе с exe файлом создаст и файл .xml, дайте ему соответствующее имя и нажмите “Save”. Файл .xml является стандартным, не волнуйтесь об этом. Сразу после создания .xml файла будет создан exe файл.