Я хотел бы определить операционную систему хоста, на которой моя программа Java работает программно (например: я хотел бы иметь возможность загружать различные свойства в зависимости от того, нахожусь ли я на платформе Windows или Unix). Как наиболее безопасный способ сделать это со 100% надежностью?




Вы можете использовать:
System.getProperty("os.name")
P.S. Вы можете найти этот код полезным:
class ShowProperties {
public static void main(String[] args) {
System.getProperties().list(System.out);
}
}
Все, что он делает, это распечатывает все свойства, предоставляемые вашими реализациями Java. Это даст вам представление о том, что вы можете узнать о своей среде Java с помощью свойств. :-)
nvm найдено stackoverflow.com/questions/31909107/…
Октябрь 2008 г .:
Я бы рекомендовал кешировать его в статической переменной:
public static final class OsUtils
{
private static String OS = null;
public static String getOsName()
{
if (OS == null) { OS = System.getProperty("os.name"); }
return OS;
}
public static boolean isWindows()
{
return getOsName().startsWith("Windows");
}
public static boolean isUnix() // and so on
}
Таким образом, каждый раз, когда вы запрашиваете ОС, вы не получаете свойство более одного раза за время существования вашего приложения.
Февраль 2016: 7+ лет спустя:
В Windows 10 есть ошибка (которой не было на момент первоначального ответа) .
См. "«Os.name» Java для Windows 10?"
Я согласен с функцией getOSName на основе OAOO (один раз и только один раз); однако кеширование полностью избыточно, учитывая скорость поиска хэшей.
Полная избыточность может быть немного жесткой, поиск хэша дороже, чем доступ к ссылке. Все зависит от контекста.
Хорошие моменты ... Не стесняйтесь голосовать против, если вы считаете, что это плохая практика;)
Я перечитал этот ответ. Если вы собираетесь кэшировать, кешируйте значения isWindows, isUnix и т. д. Таким образом вы также экономите время сравнения строк.
@ ChrisJester-Young Я согласен (я не помню этот ответ, которому более 6,5 лет). Не могли бы вы отредактировать его соответственно?
@Brian True. Я соответствующим образом отредактировал этот очень старый ответ, чтобы сослаться на более свежий.
Во времена Windows 10 вы можете себе представить, почему это было плохой практикой. Пожалуйста, не делайте if (getOsName().startsWith("Windows 9")) { /* 95 and 98 */ } else { }
Если вам интересно, как проект с открытым исходным кодом делает подобные вещи, вы можете проверить класс Terracotta (Os.java), который обрабатывает этот мусор здесь:
И вы можете увидеть аналогичный класс для обработки версий JVM (Vm.java и VmVersion.java) здесь:
Этот класс Terracotta довольно обширен!
также страдает той же проблемой, которая была определена Джеймсом Ропером в Ответ Вольфганга Фаля - использование toLowerCase без указания локали
Я считаю, что Утилиты ОС от Swingx выполняет свою работу.
Вышеупомянутая ссылка кажется неработающей, вероятно, из-за того, что SwingX представляет ветки; релиз 1.6 здесь: swingx.dev.java.net/source/browse/swingx/tags/SwingX-1-6/src /…
@ Дэвид Молес, спасибо. ссылка была в порядке, когда я ответил - теперь я обновил ее на вашу.
Последняя версия находится здесь: java.net/projects/swingx/sources/svn/content/trunk/swingx-co re /…
Как указано в других ответах, System.getProperty предоставляет необработанные данные. Однако Компонент Apache Commons Lang предоставляет оболочка для java.lang.System удобные свойства, такие как SystemUtils.IS_OS_WINDOWS, во многом аналогичные вышеупомянутой утилите Swingx OS.
Это действительно удобно. Вы открываете для себя новые функции Apache Lang3 каждый день!
String osName = System.getProperty("os.name");
System.out.println("Operating system " + osName);
Небольшим примером того, чего вы пытаетесь достичь, вероятно, будет class, похожий на то, что внизу:
import java.util.Locale;
public class OperatingSystem
{
private static String OS = System.getProperty("os.name", "unknown").toLowerCase(Locale.ROOT);
public static boolean isWindows()
{
return OS.contains("win");
}
public static boolean isMac()
{
return OS.contains("mac");
}
public static boolean isUnix()
{
return OS.contains("nux");
}
}
Эта конкретная реализация достаточно надежна и должна быть универсальной. Просто скопируйте и вставьте его в выбранный вами class.
некоторые ссылки в ответах выше кажутся неработающими. Я добавил указатели на текущий исходный код в приведенный ниже код и предлагаю подход для обработки проверки с перечислением в качестве ответа, чтобы оператор switch можно было использовать при оценке результата:
OsCheck.OSType ostype=OsCheck.getOperatingSystemType();
switch (ostype) {
case Windows: break;
case MacOS: break;
case Linux: break;
case Other: break;
}
Вспомогательный класс:
/**
* helper class to check the operating system this Java VM runs in
*
* please keep the notes below as a pseudo-license
*
* http://stackoverflow.com/questions/228477/how-do-i-programmatically-determine-operating-system-in-java
* compare to http://svn.terracotta.org/svn/tc/dso/tags/2.6.4/code/base/common/src/com/tc/util/runtime/Os.java
* http://www.docjar.com/html/api/org/apache/commons/lang/SystemUtils.java.html
*/
import java.util.Locale;
public static final class OsCheck {
/**
* types of Operating Systems
*/
public enum OSType {
Windows, MacOS, Linux, Other
};
// cached result of OS detection
protected static OSType detectedOS;
/**
* detect the operating system from the os.name System property and cache
* the result
*
* @returns - the operating system detected
*/
public static OSType getOperatingSystemType() {
if (detectedOS == null) {
String OS = System.getProperty("os.name", "generic").toLowerCase(Locale.ENGLISH);
if ((OS.indexOf("mac") >= 0) || (OS.indexOf("darwin") >= 0)) {
detectedOS = OSType.MacOS;
} else if (OS.indexOf("win") >= 0) {
detectedOS = OSType.Windows;
} else if (OS.indexOf("nux") >= 0) {
detectedOS = OSType.Linux;
} else {
detectedOS = OSType.Other;
}
}
return detectedOS;
}
}
(OS.indexOf ("darwin")> = 0) никогда не может быть истинным, потому что оно идет после (OS.indexOf ("win")> = 0)
Код выше май имеет проблемы с локалью, поскольку он использует toLowerCase (), который зависит от языкового стандарта. Это особенно важно при преобразовании i в нижний / верхний регистр, поскольку в Турции I становится строчным без точки i (ı), а i становится прописным с точками i (İ). Таким образом, "WINDOWS" .toLowerCase (). IndexOf ("win") вернет -1 в Турции. Всегда передавайте локаль при вводе строчных букв определенного языка, например "WINDOWS" .toLowerCase (Locale.ENGLISH) .indexOf ("win") будет работать в Турции.
@JamesRoper - спасибо исправил это.
Мне понравился ответ Вольфганга просто потому, что я считаю, что такие вещи должны быть константами ...
поэтому я немного перефразировал это для себя и подумал поделиться им :)
/**
* types of Operating Systems
*
* please keep the note below as a pseudo-license
*
* helper class to check the operating system this Java VM runs in
* http://stackoverflow.com/questions/228477/how-do-i-programmatically-determine-operating-system-in-java
* compare to http://svn.terracotta.org/svn/tc/dso/tags/2.6.4/code/base/common/src/com/tc/util/runtime/Os.java
* http://www.docjar.com/html/api/org/apache/commons/lang/SystemUtils.java.html
*/
public enum OSType {
MacOS("mac", "darwin"),
Windows("win"),
Linux("nux"),
Other("generic");
private static OSType detectedOS;
private final String[] keys;
private OSType(String... keys) {
this.keys = keys;
}
private boolean match(String osKey) {
for (int i = 0; i < keys.length; i++) {
if (osKey.indexOf(keys[i]) != -1)
return true;
}
return false;
}
public static OSType getOS_Type() {
if (detectedOS == null)
detectedOS = getOperatingSystemType(System.getProperty("os.name", Other.keys[0]).toLowerCase());
return detectedOS;
}
private static OSType getOperatingSystemType(String osKey) {
for (OSType osType : values()) {
if (osType.match(osKey))
return osType;
}
return Other;
}
}
Кажется, что "darwin" никогда не может быть сопоставлен, потому что проверка "win" уже приведет к возврату Windows.
см. исправление в моем исходном ответе
Поздравляем, вы повторно реализовали sun.awt.OSInfo # getOSType :)
ХХХХХ ... хороший ... @Kirill Gamazkov Я не нашел тогда ... спасибо, что указали на это
Попробуйте это просто и легко
System.getProperty("os.name");
System.getProperty("os.version");
System.getProperty("os.arch");
Этот код для отображения всей информации о типе операционной системы, имени, java-информации и так далее.
public static void main(String[] args) {
// TODO Auto-generated method stub
Properties pro = System.getProperties();
for(Object obj : pro.keySet()){
System.out.println(" System "+(String)obj+" : "+System.getProperty((String)obj));
}
}
В приведенном ниже коде показаны значения, которые вы можете получить из системного API, это все, что вы можете получить с помощью этого API.
public class App {
public static void main( String[] args ) {
//Operating system name
System.out.println(System.getProperty("os.name"));
//Operating system version
System.out.println(System.getProperty("os.version"));
//Path separator character used in java.class.path
System.out.println(System.getProperty("path.separator"));
//User working directory
System.out.println(System.getProperty("user.dir"));
//User home directory
System.out.println(System.getProperty("user.home"));
//User account name
System.out.println(System.getProperty("user.name"));
//Operating system architecture
System.out.println(System.getProperty("os.arch"));
//Sequence used by operating system to separate lines in text files
System.out.println(System.getProperty("line.separator"));
System.out.println(System.getProperty("java.version")); //JRE version number
System.out.println(System.getProperty("java.vendor.url")); //JRE vendor URL
System.out.println(System.getProperty("java.vendor")); //JRE vendor name
System.out.println(System.getProperty("java.home")); //Installation directory for Java Runtime Environment (JRE)
System.out.println(System.getProperty("java.class.path"));
System.out.println(System.getProperty("file.separator"));
}
}
Ответы: -
Windows 7
6.1
;
C:\Users\user\Documents\workspace-eclipse\JavaExample
C:\Users\user
user
amd64
1.7.0_71
http://java.oracle.com/
Oracle Corporation
C:\Program Files\Java\jre7
C:\Users\user\Documents\workspace-Eclipse\JavaExample\target\classes
\
TL; DR
Для доступа к ОС используйте: System.getProperty("os.name").
Но почему бы не создать служебный класс, сделать его многоразовым! И, вероятно, намного быстрее при нескольких вызовах. Чисто, понятно, быстрее!
Создайте класс Util для таких служебных функций. Затем создайте общедоступные перечисления для каждого типа операционной системы.
public class Util {
public enum OS {
WINDOWS, LINUX, MAC, SOLARIS
};// Operating systems.
private static OS os = null;
public static OS getOS() {
if (os == null) {
String operSys = System.getProperty("os.name").toLowerCase();
if (operSys.contains("win")) {
os = OS.WINDOWS;
} else if (operSys.contains("nix") || operSys.contains("nux")
|| operSys.contains("aix")) {
os = OS.LINUX;
} else if (operSys.contains("mac")) {
os = OS.MAC;
} else if (operSys.contains("sunos")) {
os = OS.SOLARIS;
}
}
return os;
}
}
Теперь вы можете легко вызвать класс из любого класса следующим образом (P.S. Поскольку мы объявили переменную os как статическую, ей потребуется время только один раз, чтобы определить тип системы, затем ее можно использовать, пока ваше приложение не остановится.)
switch (Util.getOS()) {
case WINDOWS:
//do windows stuff
break;
case LINUX:
и это все!
Я хочу использовать этот фрагмент кода в проекте с открытым исходным кодом (github.com/openhab/openhab-addons), вас это устраивает?
Да, пожалуйста, не стесняйтесь его использовать.
Вы можете просто использовать метод sun.awt.OSInfo # getOSType ()
Это должен быть лучший ответ! Я просто проверял, не упоминал ли кто об этом здесь.
Есть ли способ обхода этого «ограниченного API»? Я бы хотел попробовать использовать это, но он дает мне такое предупреждение в Eclipse. Я могу использовать более старую версию jre (например, jre1.8.0_171), но в последней версии 1.8 jres она помечена как ограниченная.
Весь пакет sun устарел, я не могу представить, как это можно обойти. Кажется, что это просто System.getProperty("os.name"), а затем проверяется, содержит ли свойство «Windows», «Linux», «Solaris» или «OS X», так что это в основном то же самое, что и ответ Вишала Чаудхари.
Следующие классы JavaFX имеют статические методы для определения текущей ОС (isWindows (), isLinux () ...):
Пример:
if (PlatformUtil.isWindows()){
...
}
это должно быть выше
Обратите внимание, что доступ к "com / sun / javafx / *" сейчас не рекомендуется (проверено с помощью JDK 1.8.0_121).
@MichaelMarton У вас есть ссылка на ваше заявление?
@HummelingEngineeringBV: Думаю, это была моя ошибка. Я работаю с eclipse Neon 4.6.3, и «Путь сборки Java» показывает несколько предупреждений «Не рекомендуется: com / sun / javafx / **». Однако, как я выяснил, это ошибка eclipse-bug и / или -feature (см. связь).
Я должен исправить себя еще раз. Начиная с Java 9/10 +, несколько пакетов / API "com.sun. *" Будут удалены. Ознакомьтесь с эта ссылка для получения дополнительной информации. Я действительно наткнулся на это, потому что мы используем некоторые из этих пакетов. При переходе на eclipse 4.8 / JDK 10 мы теперь должны исправить эти и несколько других ошибок компилятора из-за отсутствия ссылок.
Я думаю, что следующее может дать более широкий охват в меньшем количестве строк
import org.apache.commons.exec.OS;
if (OS.isFamilyWindows()){
//load some property
}
else if (OS.isFamilyUnix()){
//load some other property
}
Подробнее здесь: https://commons.apache.org/proper/commons-exec/apidocs/org/apache/commons/exec/OS.html
В классе com.sun.jna.Platform вы можете найти полезные статические методы, такие как
Platform.isWindows();
Platform.is64Bit();
Platform.isIntel();
Platform.isARM();
и многое другое.
Если вы используете Maven, просто добавьте зависимость
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>5.2.0</version>
</dependency>
В противном случае просто найдите файл jar библиотеки jna (например, jna-5.2.0.jar) и добавьте его в путь к классам.
Просто используйте com.sun.javafx.util.Utils, как показано ниже.
if ( Utils.isWindows()){
// LOGIC HERE
}
ИЛИ ИСПОЛЬЗУЙТЕ
boolean isWindows = OSInfo.getOSType().equals(OSInfo.OSType.WINDOWS);
if (isWindows){
// YOUR LOGIC HERE
}
Если вы работаете в среде, где важна безопасность, прочтите, пожалуйста, это.
Пожалуйста, воздержитесь от доверия к собственности, полученной с помощью подпрограммы System#getProperty(String)! На самом деле, почти все свойства, включая os.arch, os.name и os.version, не предназначены только для чтения, как можно было бы ожидать, - наоборот, на самом деле все наоборот.
Прежде всего, любой код с достаточным разрешением на вызов подпрограммы System#setProperty(String, String) может изменять возвращаемый литерал по своему желанию. Однако это не обязательно основная проблема, поскольку ее можно решить с помощью так называемого SecurityManager, как более подробно описано в здесь.
Фактическая проблема заключается в том, что любой пользователь может редактировать эти свойства при запуске рассматриваемого JAR (через -Dos.name=, -Dos.arch= и т. д.). Возможный способ избежать подделки параметров приложения - запросить RuntimeMXBean, как показано здесь. Следующий фрагмент кода должен дать представление о том, как этого можно достичь.
RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
List<String> arguments = runtimeMxBean.getInputArguments();
for (String argument : arguments) {
if (argument.startsWith("-Dos.name") {
// System.getProperty("os.name") altered
} else if (argument.startsWith("-Dos.arch") {
// System.getProperty("os.arch") altered
}
}
File.separator не выглядит серьезным решением. Есть ли другой способ сделать это?
Да! На самом деле существует довольно элегантный способ обнаружения несанкционированного доступа к свойствам системы. Я обновлю ответ соответственно. Но имейте в виду, что проверка может только на столько - если у человека есть физический доступ к вашему приложению, будет возможно может его нарушить - независимо от того, насколько сложна проверка.
Я использую
Windows 10, ноos.nameдает мнеWindows 8.1. Это почему? Откуда это взялось?