Jak programowo określić system operacyjny w Javie?

526

Chciałbym określić system operacyjny hosta, który mój program Java uruchamia programowo (na przykład: Chciałbym móc ładować różne właściwości w zależności od tego, czy korzystam z platformy Windows, czy Unix). Jaki jest najbezpieczniejszy sposób, aby to zrobić przy 100% niezawodności?

karlgrz
źródło

Odpowiedzi:

617

Możesz użyć:

System.getProperty("os.name")

PS Ten kod może ci się przydać:

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

Wystarczy wydrukować wszystkie właściwości dostarczone przez implementacje Java. Daje ci wyobrażenie o tym, co możesz dowiedzieć się o swoim środowisku Java za pomocą właściwości. :-)

Chris Jester-Young
źródło
6
Używam, Windows 10a jednak os.namedaje mi Windows 8.1. Dlaczego? Skąd to się bierze?
Brian
152

Jak wskazano w innych odpowiedziach, System.getProperty zapewnia surowe dane. Jednak składnik Apache Commons Lang zapewnia opakowanie dla java.lang.System z przydatnymi właściwościami, takimi jak SystemUtils.IS_OS_WINDOWS, podobnie jak wyżej wspomniane użycie Swingx OS.

Leif Carlsen
źródło
2
To naprawdę przydatne. Codziennie odkrywasz nowe funkcje w Apache Lang3!
Robin Jonsson,
82

Październik 2008:

Polecam buforowanie go w zmiennej statycznej:

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
}

W ten sposób za każdym razem, gdy poprosisz o system operacyjny, nie pobierzesz właściwości więcej niż raz w ciągu całego życia aplikacji.


Luty 2016: 7+ lata później:

Wystąpił błąd w systemie Windows 10 (który nie istniał w czasie oryginalnej odpowiedzi).
Zobacz „ Java” „os.name” dla Windows 10?

VonC
źródło
5
Zgadzam się z funkcją getOSName na podstawie OAOO (raz i tylko raz); jednak buforowanie jest całkowicie zbędne, biorąc pod uwagę szybkość wyszukiwania skrótów.
Chris Jester-Young,
6
Całkowicie zbędne może być trochę trudne, wyszukiwanie skrótów jest droższe niż uzyskiwanie dostępu do odwołania. Wszystko zależy od kontekstu.
Craig Day
2
Dobre punkty ... Możesz głosować w dół, jeśli uważasz, że to zła praktyka;)
VonC
5
Ponownie przeczytam tę odpowiedź. Jeśli wybierasz się do pamięci podręcznej cache wartości isWindows, isUnixitd ten sposób można zaoszczędzić na czasie porównania ciągów również.
Chris Jester-Young
2
@Brian True. Odpowiednio zredagowałem tę bardzo starą odpowiedź, aby odnieść się do nowszej.
VCC
44

niektóre linki w powyższych odpowiedziach wydają się być zepsute. Dodałem wskaźniki do bieżącego kodu źródłowego w poniższym kodzie i oferuję podejście do obsługi sprawdzania z wyliczeniem jako odpowiedzią, aby można było użyć instrukcji switch podczas oceny wyniku:

OsCheck.OSType ostype=OsCheck.getOperatingSystemType();
switch (ostype) {
    case Windows: break;
    case MacOS: break;
    case Linux: break;
    case Other: break;
}

Klasa pomocnicza to:

/**
 * 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;
  }
}
Wolfgang Fahl
źródło
3
(OS.indexOf („darwin”)> = 0) nigdy nie może być prawdą, ponieważ następuje po nim (OS.indexOf („win”)> = 0)
William
14
Powyższy kod może powodować problemy z ustawieniami regionalnymi, ponieważ używa onLowerCase (), która jest wrażliwa na ustawienia regionalne. Tam, gdzie ma to znaczenie, szczególnie przy przekształcaniu „i” na małe / wielkie litery, ponieważ w Turcji staje się małą kropką bez kropki i (ı), a i staje się wielką kropką i (İ). Zatem „WINDOWS” .toLowerCase (). IndexOf („win”) zwróci -1 w Turcji. Zawsze wykonuj ustawienia regionalne, robiąc małe litery określonego języka, np. „WINDOWS” .toLowerCase (Locale.ENGLISH) .indexOf („win”) będzie działał w Turcji.
James Roper
@JamesRoper - dzięki temu naprawiono.
Wolfgang Fahl
7
OS.contains (...)
Grigory Kislin
42

Następujące klasy JavaFX mają statyczne metody określania bieżącego systemu operacyjnego (isWindows (), isLinux () ...):

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

Przykład:

if (PlatformUtil.isWindows()){
           ...
}
Igor Rybak
źródło
powinno być wyższe
siedliska
3
Należy pamiętać, że dostęp do „com / sun / javafx / *” jest teraz odradzany (zaznaczono to w JDK 1.8.0_121).
Michael Marton
1
@MichaelMarton Masz referencje do swojego oświadczenia?
Hummeling Engineering BV
@HummelingEngineeringBV: Myślę, że to był błąd z mojej strony. Pracuję z Eclipse Neon 4.6.3, a „Java Build Path” pokazuje kilka ostrzeżeń „Discouraged: com / sun / javafx / **”. Jednak, jak się dowiedziałem, okazuje się, że jest to błąd zaćmienia i / lub funkcja (patrz link ).
Michael Marton,
2
Muszę się jeszcze raz poprawić. Począwszy od wersji Java 9/10 +, kilka pakietów / interfejsów API „com.sun. *” Zostanie wkrótce usuniętych. Sprawdź ten link, aby uzyskać więcej informacji. Natknąłem się na to, ponieważ korzystamy z niektórych z tych pakietów. Po przejściu na środowisko Eclipse 4.8 / JDK 10 musimy teraz naprawić te i kilka innych błędów kompilatora z powodu brakujących odniesień.
Michael Marton,
16

TL; DR

Dostępu do korzystania OS: System.getProperty("os.name").


Ale dlaczego nie stworzyć klasy użyteczności, spraw, aby można ją było ponownie wykorzystać! I prawdopodobnie o wiele szybciej w przypadku wielu połączeń. Czysto, czysto, szybciej!

Utwórz klasę Util dla takich funkcji narzędziowych. Następnie utwórz publiczne wyliczenia dla każdego typu systemu operacyjnego.

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;
    }
}

Teraz możesz łatwo wywoływać klasę z dowolnej klasy w następujący sposób (PS Ponieważ zadeklarowaliśmy zmienną os jako statyczną, identyfikacja typu systemu zajmie czas tylko raz, więc można jej używać do momentu zatrzymania aplikacji).

            switch (Util.getOS()) {
            case WINDOWS:
                //do windows stuff
                break;
            case LINUX:

i to jest to!

Memin
źródło
2
Chcę użyć tego fragmentu kodu w projekcie typu open source ( github.com/openhab/openhab-addons ), czy to w porządku?
Consti P
Tak, możesz go używać.
Memin
13

Mały przykład tego, co próbujesz osiągnąć, prawdopodobnie byłby classpodobny do tego, co poniżej:

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");
    }
}

Ta konkretna implementacja jest dość niezawodna i powinna mieć uniwersalne zastosowanie. Po prostu skopiuj i wklej go do swojego classwyboru.

Nikesh Jauhari
źródło
10

Jeśli jesteś zainteresowany tym, jak projekt open source robi takie rzeczy, możesz sprawdzić klasę terakoty (Os.java), która obsługuje te śmieci tutaj:

I możesz zobaczyć podobną klasę do obsługi wersji JVM (Vm.java i VmVersion.java) tutaj:

Alex Miller
źródło
2
Ta klasa terakoty jest dość kompleksowa!
Stewart
3
strzeżcie się licencji!
harschware
cierpi również na ten sam problem zidentyfikowany przez Jamesa Roper'a w odpowiedzi Wolfganga Fahla - użycie toLowerCasebez określenia lokalizacji
kbolino
9

Wypróbuj to, proste i łatwe

System.getProperty("os.name");
System.getProperty("os.version");
System.getProperty("os.arch");
Kamidu
źródło
9

Zaczerpnięte z tego projektu https://github.com/RishiGupta12/serial-communication-manager

String osName = System.getProperty("os.name");
String osNameMatch = osName.toLowerCase();
if(osNameMatch.contains("linux")) {
    osType = OS_LINUX;
}else if(osNameMatch.contains("windows")) {
    osType = OS_WINDOWS;
}else if(osNameMatch.contains("solaris") || osNameMatch.contains("sunos")) {
    osType = OS_SOLARIS;
}else if(osNameMatch.contains("mac os") || osNameMatch.contains("macos") || osNameMatch.contains("darwin")) {
    osType = OS_MAC_OS_X;
}else {
}
John Miller
źródło
8

Poniższy kod pokazuje wartości, które można uzyskać z System API, wszystkie te rzeczy, które można uzyskać za pośrednictwem tego 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"));
    }
}

Odpowiedzi: -

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
\
Ash_P
źródło
7

Uważam, że Utils OS Swils wykonuje pracę.

Richard Harrison
źródło
2
Powyższy link wydaje się być zepsuty, prawdopodobnie z powodu wprowadzenia gałęzi SwingX; Wydanie 1.6 jest tutaj: swingx.dev.java.net/source/browse/swingx/tags/SwingX-1-6/src/…
David Moles
1
@David Moles, dzięki. link był w porządku, kiedy odpowiedziałem - zaktualizowałem go teraz o twój.
Richard Harrison
2
Najnowsza wersja jest tutaj: java.net/projects/swingx/sources/svn/content/trunk/swingx-core/…
Vladislav Rastrusny
5
String osName = System.getProperty("os.name");
System.out.println("Operating system " + osName);
Vishal Chaudhari
źródło
4

Możesz po prostu użyć metody sun.awt.OSInfo # getOSType ()

Kirill Gamazkov
źródło
To powinna być najlepsza odpowiedź! Właśnie sprawdzałem, czy ktoś już o tym nie wspomniał.
Martin Krajčírovič
Jakieś obejście tego „ograniczonego API”? Chciałbym spróbować tego użyć, ale daje mi to ostrzeżenie w Eclipse. Mogę użyć starszego środowiska Jre (np. Jre1.8.0_171), ale najnowsze jres 1.8 mają oznaczony jako ograniczony.
Brian_Entei
4

Jeśli pracujesz w środowisku wrażliwym na bezpieczeństwo, przeczytaj to.

Proszę, nigdy nie ufajcie nieruchomości uzyskanej za pomocą System#getProperty(String)podprogramu! W rzeczywistości prawie każda właściwość, w tym os.arch, os.namei, os.versionnie jest tylko do odczytu, jak można się spodziewać - zamiast tego są wręcz przeciwnie.

Przede wszystkim każdy kod z wystarczającą zgodą na wywołanie System#setProperty(String, String)podprogramu może dowolnie modyfikować zwracany literał. Jednak nie jest to koniecznie główny problem, ponieważ można go rozwiązać za pomocą tak zwanego SecurityManager, jak opisano bardziej szczegółowo tutaj .

Rzeczywistym problemem jest to, że każdy użytkownik może edytować te właściwości podczas uruchamiania danego JARpytania. Oznacza to, że nie ma sposobu, aby ustalić, czy te właściwości są rzeczywiście dokładne. Z tego powodu oto kilka dodatkowych sprawdzeń, aby uniknąć manipulacji:

// The first thing we're able to do is to query the filesystem.
switch (java.io.File.separator)
{
    case "/":
        // Windows is a potential candidate.
        break;
    case "\\":
        // And here it could really be anything else.
        break;
    default:
        // There's probably something really wrong here by now.
        break;
}

Innym dobrym pomysłem jest sprawdzenie obecności katalogów specyficznych dla systemu operacyjnego. Niezależnie od tego, jakie podejmiesz podejście, pamiętaj, że język Java jest przeznaczony dla wielu platform. Dlaczego więc nie spróbujesz zrobić tego samego?

Niklas Simandi
źródło
3

Podoba mi się odpowiedź Wolfganga tylko dlatego, że uważam, że takie rzeczy powinny być consts ...

więc sformułowałem to trochę dla siebie i postanowiłem to udostępnić :)

/**
 * 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;
    }
}
TacB0sS
źródło
Wygląda na to, że „darwin” nigdy nie może być dopasowany, ponieważ sprawdzenie „win” już spowodowałoby zwrócenie systemu Windows.
tvkanters
patrz poprawka w mojej oryginalnej odpowiedzi
Wolfgang Fahl
3
Gratulacje, ponownie wdrożyłeś sun.awt.OSInfo # getOSType :)
Kirill Gamazkov
HHHHH ... dobry ... @Kirill Gamazkov Wtedy go nie znalazłem .. dziękuję za zwrócenie uwagi
TacB0sS
2

Ten kod do wyświetlania wszystkich informacji o typie systemu operacyjnego, nazwie, informacjach Java i tak dalej.

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));
    }
}
ShinnedHawks
źródło
1

W klasie com.sun.jna.Platform można znaleźć przydatne metody statyczne, takie jak

Platform.isWindows();
Platform.is64Bit();
Platform.isIntel();
Platform.isARM();

i wiele więcej.

Jeśli używasz Maven, po prostu dodaj zależność

<dependency>
 <groupId>net.java.dev.jna</groupId>
 <artifactId>jna</artifactId>
 <version>5.2.0</version>
</dependency>

W przeciwnym razie po prostu znajdź plik jar biblioteki jna (np. Jna-5.2.0.jar) i dodaj go do ścieżki klasy.

Vladimir Vaschenko
źródło
1

Po prostu użyj com.sun.javafx.util.Utilsjak poniżej.

if ( Utils.isWindows()){
     // LOGIC HERE
}

ALBO UŻYJ

boolean isWindows = OSInfo.getOSType().equals(OSInfo.OSType.WINDOWS);
       if (isWindows){
         // YOUR LOGIC HERE
       }
itro
źródło