ฉันจะกำหนดระบบปฏิบัติการโดยใช้โปรแกรมใน Java ได้อย่างไร


526

ฉันต้องการพิจารณาระบบปฏิบัติการของโฮสต์ที่โปรแกรม Java ของฉันใช้งานโดยทางโปรแกรม (ตัวอย่างเช่น: ฉันต้องการโหลดคุณสมบัติที่แตกต่างกันโดยขึ้นอยู่กับว่าฉันอยู่บนแพลตฟอร์ม Windows หรือ Unix) วิธีที่ปลอดภัยที่สุดในการทำเช่นนี้คือความน่าเชื่อถือ 100%

คำตอบ:


617

คุณสามารถใช้ได้:

System.getProperty("os.name")

PS คุณอาจพบว่ารหัสนี้มีประโยชน์:

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

ทั้งหมดนี้คือพิมพ์คุณสมบัติทั้งหมดที่มีให้โดยการปรับใช้ Java ของคุณ มันจะทำให้คุณทราบถึงสิ่งที่คุณสามารถค้นหาเกี่ยวกับสภาพแวดล้อม Java ของคุณผ่านคุณสมบัติ :-)


6
ฉันใช้Windows 10และยังให้ฉันos.name Windows 8.1ทำไมถึงเป็นอย่างนั้น? สิ่งนี้มาจากไหน
Brian


152

ตามที่ระบุไว้ในคำตอบอื่น ๆ System.getProperty ให้ข้อมูลดิบ อย่างไรก็ตามส่วนประกอบ Apache Commons Langเป็นตัวห่อหุ้มสำหรับ java.lang.Systemพร้อมคุณสมบัติที่มีประโยชน์เช่นSystemUtils.IS_OS_WINDOWSเดียวกับ Swingx OS ดังกล่าวข้างต้น


2
มันมีประโยชน์จริงๆ คุณค้นพบคุณสมบัติใหม่ใน Apache Lang3 ทุกวัน!
Robin Jonsson

82

ต.ค. 2551:

ฉันอยากจะแนะนำให้แคชในตัวแปรคงที่:

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 ได้หรือไม่ "


5
ฉันเห็นด้วยกับฟังก์ชั่น getOSName บนพื้นฐานของ OAOO (ครั้งเดียวและครั้งเดียว); อย่างไรก็ตามการแคชซ้ำซ้อนโดยสิ้นเชิงเมื่อความเร็วของการค้นหาแฮช
Chris Jester-Young

6
ซ้ำซ้อนโดยสิ้นเชิงอาจจะค่อนข้างรุนแรงการค้นหาแฮชมีราคาแพงกว่าการเข้าถึงข้อมูลอ้างอิง ทุกอย่างขึ้นอยู่กับบริบท
Craig Day

2
คะแนนดี ... อย่าลังเลที่จะลงคะแนนถ้าคุณคิดว่าเป็นการปฏิบัติที่ไม่ดี;)
VonC

5
ฉันอ่านคำตอบนี้อีกครั้ง หากคุณกำลังจะไปยังแคชแคชค่าของisWindows, isUnixฯลฯ นั่นวิธีการที่คุณประหยัดเวลาการเปรียบเทียบสตริงยัง
Chris Jester-Young

2
@Brian True ฉันได้แก้ไขคำตอบที่เก่ามากนี้เพื่ออ้างอิงถึงคำตอบล่าสุด
VonC

44

ลิงก์บางส่วนในคำตอบข้างต้นดูเหมือนจะใช้งานไม่ได้ ฉันได้เพิ่มพอยน์เตอร์ไปยังซอร์สโค้ดปัจจุบันในโค้ดด้านล่างและเสนอแนวทางสำหรับการจัดการเช็คด้วย enum เป็นคำตอบเพื่อให้สามารถใช้คำสั่ง 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;
  }
}

3
(OS.indexOf ("darwin")> = 0) ไม่สามารถเป็นจริงได้เพราะมันมาหลังจาก (OS.indexOf ("win")> = 0)
William

14
รหัสด้านบนอาจมีปัญหาสถานที่เนื่องจากมันใช้ toLowerCase () ซึ่งเป็นสถานที่สำคัญ เมื่อเรื่องนี้เกิดขึ้นโดยเฉพาะอย่างยิ่งเมื่อแปลง i เป็นตัวเล็ก / ตัวใหญ่เนื่องจากในตุรกีฉันจะกลายเป็นตัวพิมพ์เล็กที่ไม่ได้เชื่อมโยง i (ı) และฉันกลายเป็นตัวพิมพ์ใหญ่แบบประ i (İ) ดังนั้น "WINDOWS" .toLowerCase (). indexOf ("win") จะส่งคืน -1 ในตุรกี ส่งโลแคลเมื่อทำตัวพิมพ์เล็กของภาษาเฉพาะเช่น "WINDOWS" .toLowerCase (Locale.ENGLISH) .indexOf ("win") จะทำงานในตุรกี
James Roper

@JamesRoper - thanx แก้ไขสิ่งนี้
Wolfgang Fahl

7
OS.contain (... )
Grigory Kislin

42

คลาส JavaFX ต่อไปนี้มีวิธีการแบบสแตติกเพื่อกำหนด OS ปัจจุบัน (isWindows (), isLinux () ... ):

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

ตัวอย่าง:

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

สิ่งนี้ควรสูงกว่านี้
แหล่งที่อยู่อาศัย

3
โปรดทราบว่าการเข้าถึง "com / sun / javafx / *" ไม่ได้รับการสนับสนุนในขณะนี้ (ตรวจสอบด้วย JDK 1.8.0_121)
Michael Marton

1
@MichaelMarton มีการอ้างอิงสำหรับคำสั่งของคุณหรือไม่
Hummeling Engineering BV

@HummelingEngineeringBV: ฉันคิดว่ามันเป็นความผิดพลาดจากด้านข้างของฉัน ฉันกำลังทำงานกับ eclipse Neon 4.6.3 และคำแนะนำ "Java Build Path" แสดงคำเตือนหลายคำว่า "หมดกำลังใจ: com / sun / javafx / **" อย่างไรก็ตามอย่างที่ฉันทราบนี่เป็น eclipse-bug และ / หรือ -feature (ดูลิงค์ )
Michael Marton

2
ฉันต้องแก้ไขตัวเองอีกครั้ง เริ่มต้นด้วย Java 9/10 + จะมีการลบแพ็กเกจ "com.sun. *" หลายรายการ / API ลองดูที่ลิงค์นี้สำหรับข้อมูลเพิ่มเติม ที่จริงแล้วฉันสะดุดเพราะเราใช้แพ็คเกจเหล่านี้ การย้ายไปยัง eclipse 4.8 / JDK 10 ตอนนี้เราต้องแก้ไขข้อผิดพลาดเหล่านี้และคอมไพเลอร์อื่น ๆ อีกหลายอันเนื่องจากการอ้างอิงที่ขาดหายไป
Michael Marton

16

TL; DR

สำหรับการเข้าถึงการใช้ระบบปฏิบัติการ: System.getProperty("os.name").


แต่ทำไมไม่สร้างคลาสยูทิลิตี้ทำให้มันสามารถใช้ซ้ำได้! และอาจเร็วกว่ามากในการโทรหลายสาย สะอาดชัดเจนเร็วขึ้น!

สร้างคลาส Util สำหรับฟังก์ชั่นยูทิลิตี้ดังกล่าว จากนั้นสร้าง enums สาธารณะสำหรับระบบปฏิบัติการแต่ละประเภท

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

ตอนนี้คุณสามารถเรียกคลาสจากคลาสใด ๆ ได้อย่างง่ายดายดังนี้ (PS เนื่องจากเราประกาศว่าตัวแปรระบบปฏิบัติการเป็นแบบสแตติกมันจะใช้เวลาเพียงครั้งเดียวในการระบุประเภทของระบบจากนั้นมันจะสามารถใช้งานได้

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

และนั่นคือมัน!


2
ฉันต้องการใช้รหัสนี้ในโครงการโอเพนซอร์ซ ( github.com/openhab/openhab-addons ) มันโอเคกับคุณหรือไม่
Consti P

ใช่โปรดใช้มัน
Memin

13

ตัวอย่างเล็ก ๆ ของสิ่งที่คุณพยายามบรรลุอาจเป็น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ตัวเลือกที่คุณต้องการ


10

หากคุณสนใจว่าโครงการโอเพ่นซอร์สจะทำสิ่งนี้อย่างไรคุณสามารถดูคลาส Terracotta (Os.java) ที่จัดการขยะนี้ได้ที่นี่:

และคุณสามารถดูคลาสที่คล้ายกันเพื่อจัดการเวอร์ชัน JVM (Vm.java และ VmVersion.java) ที่นี่:


2
คลาส Terracotta นั้นค่อนข้างครอบคลุม!
สจ๊วต

3
ระวังใบอนุญาต !!
harschware

ยังทนทุกข์ทรมานจากปัญหาเดียวกันที่ระบุโดย James Roper ในคำตอบของ Wolfgang Fahl - การใช้toLowerCaseโดยไม่ระบุสถานที่
kbolino

9

ลองใช้วิธีนี้ง่ายและสะดวก

System.getProperty("os.name");
System.getProperty("os.version");
System.getProperty("os.arch");

9

นำมาจากโครงการนี้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 {
}

8

โค้ดด้านล่างแสดงค่าที่คุณได้รับจาก System 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
\

7

ฉันพบว่าOS Utils จาก Swingxทำงานได้


2
ลิงค์ด้านบนดูเหมือนว่าจะใช้งานไม่ได้อาจเป็นเพราะ SwingX แนะนำสาขา 1.6 รีลีสอยู่ที่นี่: swingx.dev.java.net/source/browse/swingx/tags/SwingX-1-6/src/ …
David Moles

1
@ David Moles ขอบคุณ ลิงค์ก็ใช้ได้เมื่อฉันตอบ - ฉันได้อัปเดตกับคุณแล้ว
Richard Harrison

2
รุ่นล่าสุดอยู่ที่นี่: java.net/projects/swingx/sources/svn/content/trunk/swingx-core/…
Vladislav Rastrusny

6

ฉันคิดว่าการติดตามสามารถให้ความครอบคลุมที่กว้างขึ้นในบรรทัดที่น้อยลง

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



4

คุณสามารถใช้วิธี sun.awt.OSInfo # getOSType ()


นี่ควรเป็นคำตอบที่ดีที่สุด! ฉันแค่ตรวจสอบว่ามีคนพูดถึงเรื่องนี้ที่นี่แล้ว
Martin Krajčírovič

วิธีแก้ปัญหาใด ๆ สำหรับสิ่งนี้คือ 'API ที่ จำกัด ' ฉันต้องการลองใช้สิ่งนี้ แต่มันเตือนฉันใน Eclipse ฉันสามารถใช้ jre รุ่นเก่ากว่า (เช่น jre1.8.0_171) แต่รุ่น 1.8 jres ล่าสุดมีการทำเครื่องหมายว่าถูก จำกัด
Brian_Entei

4

หากคุณกำลังทำงานในสภาพแวดล้อมที่มีความอ่อนไหวด้านความปลอดภัยโปรดอ่านผ่าน

โปรดหลีกเลี่ยงการไว้วางใจทรัพย์สินที่ได้รับผ่านSystem#getProperty(String)รูทีนย่อย! อันที่จริงเกือบทุกสถานที่ให้บริการรวมทั้งos.arch, os.nameและos.versionไม่ได้อ่านได้อย่างเดียวตามที่คุณอาจคาดหวัง - แทนพวกเขากำลังจริงค่อนข้างตรงข้าม

ประการแรกโค้ดใด ๆ ที่มีสิทธิ์เพียงพอในการเรียกSystem#setProperty(String, String)รูทีนย่อยสามารถแก้ไขตัวอักษรที่ส่งคืนได้ตามต้องการ อย่างไรก็ตามนั่นไม่จำเป็นว่าจะเป็นปัญหาหลักที่นี่เนื่องจากสามารถแก้ไขได้โดยการใช้สิ่งที่เรียกว่าSecurityManagerดังที่อธิบายในรายละเอียดที่นี่ที่นี่

ปัญหาที่แท้จริงคือผู้ใช้ทุกคนสามารถแก้ไขคุณสมบัติเหล่านี้เมื่อเรียกใช้JARในปัญหา ซึ่งหมายความว่าไม่มีทางที่จะตัดสินได้ว่าคุณสมบัติเหล่านี้มีความถูกต้องจริงหรือไม่ ด้วยเหตุนี้จึงมีการตรวจสอบเพิ่มเติมอีกสองสามข้อเพื่อลองและหลีกเลี่ยงการแก้ไข:

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

อีกความคิดที่ดีคือการตรวจสอบการมีไดเรกทอรีเฉพาะระบบปฏิบัติการ ไม่ว่าคุณจะใช้วิธีใดโปรดจำไว้ว่าภาษาJavaนั้นถูกเยื้องเป็นแพลตฟอร์มข้าม ดังนั้นทำไมคุณไม่ลองทำแบบเดียวกันล่ะ


3

ฉันชอบคำตอบของ Wolfgang เพียงเพราะฉันเชื่อในสิ่งที่ควรจะเป็น ...

ดังนั้นฉันจึงได้เรียบเรียงใหม่ให้กับตัวเองและคิดว่าจะแบ่งปัน :)

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

ดูเหมือนว่าไม่สามารถจับคู่ "ดาร์วิน" ได้เนื่องจากการตรวจสอบ "ชนะ" จะทำให้ Windows กลับมาแล้ว
tvkanters

ดูการแก้ไขในคำตอบเดิมของฉัน
โวล์ฟกัง Fahl

3
ขอแสดงความยินดีคุณได้ปรับใช้ sun.awt.OSInfo # getOSType :)
Kirill Gamazkov

HHHHH ... หนึ่งที่ดี ... @Kirill Gamazkov ฉันไม่ได้พบมันในตอนนั้น .. ขอบคุณสำหรับการชี้มันออกมา
TacB0sS

2

รหัสนี้สำหรับแสดงข้อมูลทั้งหมดเกี่ยวกับประเภทระบบ os, ชื่อ, ข้อมูล 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));
    }
}

1

ในชั้น 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>

มิฉะนั้นให้หาไฟล์ jna library jar (เช่น jna-5.2.0.jar) แล้วเพิ่มลงใน classpath


1

เพียงใช้com.sun.javafx.util.Utilsดังนี้

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

หรือใช้

boolean isWindows = OSInfo.getOSType().equals(OSInfo.OSType.WINDOWS);
       if (isWindows){
         // YOUR LOGIC HERE
       }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.