如何使用Java编程确定操作系统?

626

我想通过编程方式确定我的Java程序正在运行的主机操作系统(例如:我希望能够根据是否在Windows或Unix平台上加载不同的属性)。有没有一种百分之百可靠的安全方法可以做到这一点?

22个回答

726

你可以使用:

System.getProperty("os.name")

附带一句话:你可能会发现这段代码很有用:

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

它所做的就是打印出Java实现提供的所有属性。这将为您提供有关通过属性了解您的Java环境的信息。


8
我正在使用Windows 10,但是os.name却显示为Windows 8.1。这是为什么?这个信息从哪里来的? - Brian
11
没事了,找到了这个网址:https://dev59.com/MVwZ5IYBdhLWcg3wDMm9 - Brian

196

104

2008年10月:

我建议将其缓存在静态变量中:

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年2月:7年多过去了:

Windows 10存在一个bug(原回答发布时不存在)。 请参见"Java's “os.name” for Windows 10?"


6
根据OAOO(一次且仅一次)原则,我同意getOSName函数的使用;然而,考虑到哈希查找的速度,缓存是完全多余的。 - C. K. Young
7
“完全冗余”可能有点过了,哈希查找比访问引用更昂贵。这一切取决于上下文。 - Craig Day
2
好的观点...如果您认为这是一个不好的做法,请随意给它投反对票 ;) - VonC
6
如果你要进行缓存,就缓存isWindowsisUnix等值。这样可以节省字符串比较的时间。 - C. K. Young
2
@Brian True。我已经相应地编辑了这个非常古老的答案,以引用更近期的答案。 - VonC
显示剩余2条评论

56

以上答案中的一些链接似乎已经失效。我在下面的代码中添加了指向当前源代码的指针,并提供了一种使用枚举来处理检查的方法,以便在评估结果时可以使用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
 *
 * https://dev59.com/VnVC5IYBdhLWcg3woSxW
 * 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;
  }
}

4
(OS.indexOf("darwin") >= 0) 永远不可能为真,因为它在 (OS.indexOf("win") >= 0) 之后。 - William
23
上面的代码可能存在本地化问题,因为它使用了toLowerCase(),这是与语言环境有关的。特别是在将i转换为小写/大写时,这很重要,因为在土耳其,I变成了没有点的小写i(ı),而i变成了有点的大写i(İ)。因此,在土耳其,“WINDOWS”.toLowerCase().indexOf("win")将返回-1。在执行特定语言的小写操作时,始终传递语言环境,例如"WINDOWS".toLowerCase(Locale.ENGLISH).indexOf("win")将在土耳其有效。 - James Roper
@JamesRoper - 谢谢,已经修复了。 - Wolfgang Fahl

48

以下是具有静态方法以确定当前操作系统(如isWindows()、isLinux()等)的JavaFX类:

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

示例:

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

5
请注意,现在不鼓励访问“com/sun/javafx/*”(已使用JDK 1.8.0_121进行验证)。 - Michael Marton
1
@MichaelMarton 你有支持你说法的参考资料吗? - Hummeling Engineering BV
@HummelingEngineeringBV:我想这是我的错误。我正在使用Eclipse Neon 4.6.3,而“Java Build Path”显示了几个“Discouraged: com/sun/javafx/**”警告。然而,我发现这似乎是一个Eclipse的bug和/或特性(请参见链接)。 - Michael Marton
3
我需要再次纠正自己。从Java 9/10+开始,将删除几个“com.sun.*”包/API。请查看此链接获取更多信息。实际上,我因为我们使用了其中一些包而偶然发现了这个问题。迁移到eclipse 4.8/JDK 10后,我们现在必须修复这些和其他几个编译器错误,因为缺少引用。 - Michael Marton

47

简而言之:

访问操作系统使用: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:

就是这样!


5
我想在一个开源项目中使用这段代码(https://github.com/openhab/openhab-addons),你是否同意? - Consti P
4
可以,请随意使用它。 - Memin
为什么?这并不更加简洁明了,我也怀疑它是否真的更快。 - pabrams
请说明你的理由,我很乐意修改代码,如果你有合理的证据的话。请讲清楚你的评论,这样我才能改进我7-8年前的答案。 - Memin

18

你想实现的一个小例子可能类似于下面这个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");
    }
}

这种具体实现非常可靠,适用性应该是普遍的。只需将其复制并粘贴到您选择的中。


为什么要把它搞得这么复杂?System.getProperty("os.name")就足够了。不要费心去处理那些不必要的废话。 - pabrams

12

试试这个,简单易行。

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

10

如果您正在安全敏感的环境中工作,请仔细阅读以下内容。

请勿相信通过System#getProperty(String)子例程获得的属性!实际上,几乎每个属性包括os.archos.nameos.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
是的!实际上有一种相当优雅的方法来检测系统属性的篡改。我会相应地更新答案。但请注意,检查只能做到这么多——如果一个人可以物理访问您的应用程序,无论检查有多复杂,都可能被破解 - Theikon

10

2
那个Terracotta类非常全面! - Stewart
也存在与James Roper在Wolfgang Fahl的回答中指出的相同问题--使用toLowerCase而未指定语言环境。 - kbolino

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接