Как программно определить операционную систему в Java?

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

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
564
0
394 223
19
Перейти к ответу Данный вопрос помечен как решенный

Ответы 19

Ответ принят как подходящий

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

System.getProperty("os.name")

P.S. Вы можете найти этот код полезным:

class ShowProperties {
    public static void main(String[] args) {
        System.getProperties().list(System.out);
    }
}

Все, что он делает, это распечатывает все свойства, предоставляемые вашими реализациями Java. Это даст вам представление о том, что вы можете узнать о своей среде Java с помощью свойств. :-)

Я использую Windows 10, но os.name дает мне Windows 8.1. Это почему? Откуда это взялось?

Brian 07.02.2016 22:59

nvm найдено stackoverflow.com/questions/31909107/…

Brian 07.02.2016 23:00

Октябрь 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 (один раз и только один раз); однако кеширование полностью избыточно, учитывая скорость поиска хэшей.

Chris Jester-Young 23.10.2008 08:02

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

Craig Day 23.10.2008 08:04

Хорошие моменты ... Не стесняйтесь голосовать против, если вы считаете, что это плохая практика;)

VonC 23.10.2008 08:10

Я перечитал этот ответ. Если вы собираетесь кэшировать, кешируйте значения isWindows, isUnix и т. д. Таким образом вы также экономите время сравнения строк.

Chris Jester-Young 19.03.2015 17:48

@ ChrisJester-Young Я согласен (я не помню этот ответ, которому более 6,5 лет). Не могли бы вы отредактировать его соответственно?

VonC 19.03.2015 17:49

@Brian True. Я соответствующим образом отредактировал этот очень старый ответ, чтобы сослаться на более свежий.

VonC 07.02.2016 23:18

Во времена Windows 10 вы можете себе представить, почему это было плохой практикой. Пожалуйста, не делайте if (getOsName().startsWith("Windows 9")) { /* 95 and 98 */ } else { }

Doomjunky 29.08.2017 04:41

Если вам интересно, как проект с открытым исходным кодом делает подобные вещи, вы можете проверить класс Terracotta (Os.java), который обрабатывает этот мусор здесь:

И вы можете увидеть аналогичный класс для обработки версий JVM (Vm.java и VmVersion.java) здесь:

Этот класс Terracotta довольно обширен!

Stewart 26.06.2013 18:40

также страдает той же проблемой, которая была определена Джеймсом Ропером в Ответ Вольфганга Фаля - использование toLowerCase без указания локали

kbolino 12.03.2016 17:52

Я считаю, что Утилиты ОС от Swingx выполняет свою работу.

Вышеупомянутая ссылка кажется неработающей, вероятно, из-за того, что SwingX представляет ветки; релиз 1.6 здесь: swingx.dev.java.net/source/browse/swingx/tags/SwingX-1-6/src‌ /…

David Moles 03.03.2010 17:38

@ Дэвид Молес, спасибо. ссылка была в порядке, когда я ответил - теперь я обновил ее на вашу.

Richard Harrison 03.03.2010 20:41

Последняя версия находится здесь: java.net/projects/swingx/sources/svn/content/trunk/swingx-co‌ re /…

Vladislav Rastrusny 15.06.2011 17:29

Как указано в других ответах, System.getProperty предоставляет необработанные данные. Однако Компонент Apache Commons Lang предоставляет оболочка для java.lang.System удобные свойства, такие как SystemUtils.IS_OS_WINDOWS, во многом аналогичные вышеупомянутой утилите Swingx OS.

Это действительно удобно. Вы открываете для себя новые функции Apache Lang3 каждый день!

Robin Jonsson 08.09.2016 10:28
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)

William 09.12.2013 15:32

Код выше май имеет проблемы с локалью, поскольку он использует toLowerCase (), который зависит от языкового стандарта. Это особенно важно при преобразовании i в нижний / верхний регистр, поскольку в Турции I становится строчным без точки i (ı), а i становится прописным с точками i (İ). Таким образом, "WINDOWS" .toLowerCase (). IndexOf ("win") вернет -1 в Турции. Всегда передавайте локаль при вводе строчных букв определенного языка, например "WINDOWS" .toLowerCase (Locale.ENGLISH) .indexOf ("win") будет работать в Турции.

James Roper 14.07.2014 04:40

@JamesRoper - спасибо исправил это.

Wolfgang Fahl 14.07.2014 14:16

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

поэтому я немного перефразировал это для себя и подумал поделиться им :)

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

tvkanters 29.03.2014 15:54

см. исправление в моем исходном ответе

Wolfgang Fahl 08.06.2014 16:20

Поздравляем, вы повторно реализовали sun.awt.OSInfo # getOSType :)

Kirill Gamazkov 22.01.2016 18:44

ХХХХХ ... хороший ... @Kirill Gamazkov Я не нашел тогда ... спасибо, что указали на это

TacB0sS 27.04.2018 23:13

Попробуйте это просто и легко

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), вас это устраивает?

Consti P 11.01.2020 23:29

Да, пожалуйста, не стесняйтесь его использовать.

Memin 12.01.2020 07:01

Вы можете просто использовать метод sun.awt.OSInfo # getOSType ()

Это должен быть лучший ответ! Я просто проверял, не упоминал ли кто об этом здесь.

Martin Krajčírovič 23.08.2018 20:14

Есть ли способ обхода этого «ограниченного API»? Я бы хотел попробовать использовать это, но он дает мне такое предупреждение в Eclipse. Я могу использовать более старую версию jre (например, jre1.8.0_171), но в последней версии 1.8 jres она помечена как ограниченная.

Brian_Entei 07.05.2020 19:50

Весь пакет sun устарел, я не могу представить, как это можно обойти. Кажется, что это просто System.getProperty("os.name"), а затем проверяется, содержит ли свойство «Windows», «Linux», «Solaris» или «OS X», так что это в основном то же самое, что и ответ Вишала Чаудхари.

Kirill Gamazkov 23.07.2020 14:26

Следующие классы JavaFX имеют статические методы для определения текущей ОС (isWindows (), isLinux () ...):

  • com.sun.javafx.PlatformUtil
  • com.sun.media.jfxmediaimpl.HostUtils
  • com.sun.javafx.util.Utils

Пример:

if (PlatformUtil.isWindows()){
           ...
}

это должно быть выше

habitats 20.03.2017 01:00

Обратите внимание, что доступ к "com / sun / javafx / *" сейчас не рекомендуется (проверено с помощью JDK 1.8.0_121).

Michael Marton 14.01.2018 15:27

@MichaelMarton У вас есть ссылка на ваше заявление?

Hummeling Engineering BV 10.07.2018 12:07

@HummelingEngineeringBV: Думаю, это была моя ошибка. Я работаю с eclipse Neon 4.6.3, и «Путь сборки Java» показывает несколько предупреждений «Не рекомендуется: com / sun / javafx / **». Однако, как я выяснил, это ошибка eclipse-bug и / или -feature (см. связь).

Michael Marton 11.07.2018 14:01

Я должен исправить себя еще раз. Начиная с Java 9/10 +, несколько пакетов / API "com.sun. *" Будут удалены. Ознакомьтесь с эта ссылка для получения дополнительной информации. Я действительно наткнулся на это, потому что мы используем некоторые из этих пакетов. При переходе на eclipse 4.8 / JDK 10 мы теперь должны исправить эти и несколько других ошибок компилятора из-за отсутствия ссылок.

Michael Marton 16.08.2018 23:00

Я думаю, что следующее может дать более широкий охват в меньшем количестве строк

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 не выглядит серьезным решением. Есть ли другой способ сделать это?

Čamo 25.02.2021 13:27

Да! На самом деле существует довольно элегантный способ обнаружения несанкционированного доступа к свойствам системы. Я обновлю ответ соответственно. Но имейте в виду, что проверка может только на столько - если у человека есть физический доступ к вашему приложению, будет возможно может его нарушить - независимо от того, насколько сложна проверка.

Theikon 26.02.2021 17:39

Другие вопросы по теме