我想确定我的Java程序以编程方式运行的主机的操作系统(例如:我希望能够根据我是在Windows还是Unix平台上加载不同的属性)。100%可靠的最安全的方法是什么?


当前回答

你想要实现的一个小例子可能是一个类似于下面的类:

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

这个特殊的实现非常可靠,应该是普遍适用的。只需复制粘贴到你选择的类。

其他回答

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
}

这样,每次请求o时,在应用程序的生命周期内只获取一次属性。


2016年2月:7年多后:

Windows 10有一个错误(在最初的答案时不存在)。 参见“Java的“os.name”for Windows 10?”

如果你对一个开源项目是如何做这些事情感兴趣,你可以看看Terracotta类(Os.java)在这里处理这些垃圾:

http://svn.terracotta.org/svn/tc/dso/trunk/code/base/common/src/com/tc/util/runtime/ http://svn.terracotta.org/svn/tc/dso/tags/2.6.4/code/base/common/src/com/tc/util/runtime/

你可以在这里看到类似的类来处理JVM版本(Vm.java和VmVersion.java):

http://svn.terracotta.org/svn/tc/dso/trunk/common/src/main/java/com/tc/util/runtime/

在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库jar文件(例如jna-5.2.0.jar)并将其添加到类路径。

我喜欢沃尔夫冈的回答,只是因为我相信这样的事情应该是consts……

所以我把它重新措辞了一下,并想分享一下:)

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

如果您正在安全敏感的环境中工作,那么请通读本文。

请不要相信通过system# getProperty(String)子例程获得的属性!实际上,几乎所有的属性包括os。Arch, os.name和os.name。版本并不是你所期望的只读的——相反,它们实际上恰恰相反。

首先,任何具有调用system# setProperty(String, String)子例程足够权限的代码都可以随意修改返回的文字。然而,这并不一定是这里的主要问题,因为它可以通过使用所谓的SecurityManager来解决,如这里更详细的描述。

实际的问题是,任何用户都可以在运行JAR时编辑这些属性(通过-Dos.name=, -Dos.name=, -Dos.name=)。拱=,等等)。避免篡改应用程序参数的一种可能方法是查询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
    }
}