如何在 Java 中检测类 Unix 操作系统?

Posted

技术标签:

【中文标题】如何在 Java 中检测类 Unix 操作系统?【英文标题】:How can I detect a Unix-like OS in Java? 【发布时间】:2011-03-17 23:39:08 【问题描述】:

好的,我知道System.getProperty("os.name") 会给我正在运行的操作系统的名称,但这并没有多大帮助。我需要知道的是,如果我运行的操作系统是“类 Unix”操作系统,我不在乎它是 HP-UX、AIX、Mac OS X 还是其他什么。

从list of possible os.name values 看来,检测“类Unix”操作系统的一种快速而肮脏的方法是检查os.name 是否包含“Windows”。给我的误报是我的代码不太可能遇到的操作系统!不过,如果有更好的方法,我很想知道。

【问题讨论】:

您寻找“类Unix”有什么特别的原因吗?如果您正在寻找特定功能,最好检查该功能。 “是的,通常有很多方法可以用原始 Java 解决这类问题,但有时它就是不值得麻烦”。是的,这是值得的。如果您使用 Java.io.file.list,download.oracle.com/docs/cd/E17476_01/javase/1.4.2/docs/api/… 您将获得一个目录列表,并且避免对 ls 或 dir 进行系统调用,并且避免了操作系统检测逻辑。使用独立于操作系统的 API 调用总是比摆弄操作系统检测逻辑要好。 Java 不需要该功能 ;) 作为一个额外的警告,尝试特定的命令也可能没有帮助(取决于你可能最终使用的机器)——uname、ls 等都可以在我的 Windows 机器上运行,因为我有 MinGW +MSYS 已安装... 我想检测我是否在类 Unix 操作系统上的原因是因为我正在创建目录,当在 Unix 上时,我需要“chmod”来向每个人开放写权限。我不想(或不需要)在 Windows 上运行时调用“chmod”。 AFAIK Java 没有用于更改文件权限的独立于操作系统的 API。 【参考方案1】:

使用 Commons Lang 的 org.apache.commons.lang.SystemUtils 实用程序类,它有一个很好的 IS_OS_UNIX 常量。来自 javadoc:

如果这是 POSIX 编译器,则为 true 系统,如 AIX、HP-UX、Irix、 Linux、MacOSX、Solaris 或 SUN 操作系统。

如果 OS_NAME,该字段将返回 false 为空。

然后测试变成:

if (SystemUtils.IS_OS_UNIX) 
    ...

简单、有效、易读、没有神秘的技巧。

【讨论】:

@Anders:首先,让我强调一下,我们在这里讨论的是 javadoc。您在声称它错误之前检查了实现吗?第二,列表完全错误,你会补充什么?最后一件事,请随时提交 javadoc 补丁,如果补丁可以改进某些东西,通常会受到欢迎。 上次我查看了许多不同的 Linux 发行版,即使是最古老的(Slackware)发行版也不符合 POSIX,老实说,我不相信有一个可以声称是。既不是 Solaris 也不是 SUN OS(现在确实应该是相同的),而且 MacOSX 也不兼容 POSIX。不,我没有检查实施。我将修改第一条评论,希望实现比文档更好。 @Anders:感谢您的反馈和澄清,我明白您的意思(我现在可以同意,javadoc 不好)。 确实是个好主意,如此赞成。但是使用 SystemUtils.IS_OS_WINDOWS 不是更容易吗?【参考方案2】:

我已经在 Windows XP、Vista、Win7、Mac OS 10.3 - 10.6 和各种 Linux 发行版上的生产代码中使用了您的方案,没有任何问题:

    if (System.getProperty("os.name").startsWith("Windows")) 
        // includes: Windows 2000,  Windows 95, Windows 98, Windows NT, Windows Vista, Windows XP
     else 
        // everything else
     

基本上,通过检测 Windows 来检测 类 Unix

【讨论】:

尽管发布了许多好主意(我特别喜欢 File.listRoots),但我认为这是“正确”的做法。误报的可能性很小。 如果有人在使用像 ReactOS 这样的操作系统,这不是不行吗?它当然不是类 Unix,但也不是 Windows。 @Arin。同意。八岁的答案显示它的年龄。我会把它做成社区 wiki 并参与其中。【参考方案3】:

File.listRoots() 将为您提供文件系统根目录的数组。

如果您使用的是类 Unix 系统,则该数组应包含单个条目 "/",而在 Windows 系统上,您将获得类似 ["C:", "D:", ...] 的内容

编辑: @chris_l:我完全忘记了手机。一些挖掘发现android返回一个"/\0\0" - 一个斜线后跟两个空字节(假设是一个错误)。看起来我们暂时通过运气和巧合避免了误报。很遗憾,在其他手机上找不到好的数据。

无论如何,在台式机和手机上运行相同的代码可能不是一个好主意,但知道这一点很有趣。看起来它归结为需要检查特定功能而不是简单的系统类型。

【讨论】:

我写 Java 已经很多年了,但我从来没有注意到这个函数的存在。不错! 好主意,但我想知道是否还有其他非 Windows、非 Unix 系统具有根“/”? @chris_l:大多数非 Windows、非 Unix 系统都是为特定目的和特定语言构建的研究项目,例如 Amoeba (Python) 和 House (Haskell)。这感觉像是一个逃避现实的答案,但我敢猜测他们中的大多数人都没有内置的 Java VM。撇开这个警告不谈,我不得不同意 David Thornlay 对 w.r.t 问题的评论。测试特定功能,而不是简单地类似于 Unix。 我正在考虑更多关于支持 Java 的手机 - 我不确定它们的系统根是什么。【参考方案4】:

Javadoc 说:在 UNIX 系统上,这个值 * 字段为'/';在 Microsoft Windows 系统上,它是 '\'

System.out.println( File.separatorChar == '/' ? "Unix" : "Windows" );

【讨论】:

与 listRoots 一样有效且效率更高 我一直这样做。这似乎很蹩脚,应该有更明确的东西,但它有效。 经典(OSX 之前的)Macintosh 的分隔符是“:”怎么办? @Steven:甚至还有用于 pre-OSX Macintosh 的现代 JVM 吗? @Jesper:几乎可以肯定不是,但这不是重点。您是否肯定没有使用其他分隔符,更重要的是,永远不会使用?做这样的事情充满了危险,而且你只会在路上遇到问题。【参考方案5】:

System.getProperty("os.name"); 是您将获得的最好的。

【讨论】:

【参考方案6】:

我同意 @Fuzzy 的观点,我认为 Java 希望您能够获取该信息的唯一方法是通过 os.name 属性。

我能想到的唯一其他事情是:

    拥有一个 shell 脚本或批处理文件包装器来启动您的 Java 应用程序,该应用程序使用 -D 参数将操作系统信息传递给 JVM。尽管根据您的描述,这听起来并不可行。

    您可以尝试检查是否存在特定于操作系统的目录。例如,您可以假设目录"/" 将始终存在于类 Unix 系统上,但不存在于 Windows 上,并执行以下操作:

    if((new File("/")).exists()) System.out.println("我在 Unix 系统上!");

    尝试启动一个特定于 Unix 的命令行命令,例如 ls 并检查返回码。如果它有效,那么您使用的是类 Unix 系统,否则您使用的是 Windows。

不过,所有这些解决方案实际上都只是 hack,坦率地说,我对其中的任何一个都不是很满意。不幸的是,您可能最适合您最初的想法。好玩吧?

【讨论】:

不幸的是,您的#2 解决方案不起作用。 Java 仍会返回“我在 Unix 系统上!”甚至在 Windows 上。 呸。感谢@Ferrari 的提醒。【参考方案7】:

使用 File.pathSeparator 或 File.separator。第一个将返回“;”在 Windows 中,在 Unix 中使用“:”。第二个将在 Windows 中返回“\”,在 Unix 中返回“/”。

【讨论】:

【参考方案8】:

您可以尝试执行uname 命令 - 应该适用于所有 unixoid 系统。

【讨论】:

【参考方案9】:
package com.appspot.x19290;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class UnixCheck 
    public static void main(String[] args) 
        UnixCheck s = UnixCheck.S;
        String isUnix = s.unix ? "is Unix" : "not Unix";
        try 
            System.out.println(isUnix + ", devnull: " + s.devnull.getPath());
         catch (NullPointerException e) 
            System.out.println(isUnix + ", devnull: unknown");
        
    

    public static final UnixCheck S = new UnixCheck();
    public static final UnixCheck TEST = new UnixCheck(true);

    public final boolean unix;
    public final File devnull;

    private UnixCheck() 
        this(false);
    

    private UnixCheck(boolean testing) 
        String path;
        path = testing ? "/<dev>/<no><such><null><device>" : "/dev/null";
        File devnull = devnullOrNone(path);
        if (devnull == null) 
            this.unix = false;
            path = testing ? "<no><such><null><device>" : "nul";
            this.devnull = devnullOrNone(path);
         else 
            this.unix = true;
            this.devnull = devnull;
        
    

    private static File devnullOrNone(String name) 
        File file = new File(name);
        if (file.isFile())
            return null;
        if (file.isDirectory())
            return null;
        try 
            FileInputStream i = new FileInputStream(file);
            try 
                i.read();
             finally 
                i.close();
            
         catch (IOException e) 
            return null;
        
        return file;
    

【讨论】:

这不是一个好的检查,因为您可以在 Windows 平台上拥有一个 C:/dev/null 目录......当然不是一种常见的情况,但找出程序为什么会这样可能会很痛苦在这种情况下没有正确的行为!最好检查 'os.name' 属性

以上是关于如何在 Java 中检测类 Unix 操作系统?的主要内容,如果未能解决你的问题,请参考以下文章

kettle安装部署基本操作及实操文档

mac上java环境变量配置

#私藏项目实操分享# Angular Change Detection 的学习笔记

如何在Java中检测按键

Java包循环检测:如何找到涉及的具体类? [关闭]

java笔试总结