如何使用Java确定Windows的32位或64位架构?

59

如何使用Java确定Windows的32位还是64位架构?


1
你为什么想知道这个?Java应该在任何有JVM的操作系统上运行相同 - 你的Java程序不应该关心它是否在32位或64位操作系统上运行。 - Jesper
11
@ Jesper,因为很多时候运行Java不是唯一的目的。有时你可能开发了一个程序/应用,它应该专门在64位机器上(或32位机器上)运行(原因可能是任何)。在这种情况下,我需要检查所安装的Windows架构的版本。 - Chani
6
另一个需要明确区分32位或64位操作系统的情况是,当Java程序必须启动一个外部可执行文件时,而该文件的两个版本都存在。就像编写Selenium测试时,必须启动正确的浏览器驱动程序一样。同样需要区分操作系统本身。我相信还有其他几种情况,其中一些被认为应该被“抽象化”的东西实际上并没有被抽象化。 - SantiBailors
@ Jesper 你说得没错:_假定的_。 - golimar
10个回答

78

我不太信任读取os.arch系统变量。虽然它可以在用户在64位系统上运行64位JVM时正常工作,但如果用户在64位系统上运行32位JVM,则无法正常工作。

下面的代码可以正确检测Windows 64位操作系统。在Windows 64位系统上,“Programfiles(x86)”环境变量将被设置。但在32位系统上不会设置该变量,Java 将其读取为 null。

boolean is64bit = false;
if (System.getProperty("os.name").contains("Windows")) {
    is64bit = (System.getenv("ProgramFiles(x86)") != null);
} else {
    is64bit = (System.getProperty("os.arch").indexOf("64") != -1);
}

对于像Linux、Solaris或Mac这样的其他操作系统,我们也可能会遇到这个问题。因此这并不是完整的解决方案。对于Mac来说,你可能是安全的,因为苹果将JVM锁定以匹配操作系统。但是Linux和Solaris等操作系统在64位系统上仍然可能使用32位JVM,因此请谨慎使用。


3
我并不完全信任读取 os.arch 系统变量。这种行为的原因是,例如对于 JNI 来说,了解 JVM 的架构非常重要,而不是底层操作系统(如果您需要将自己的平台相关共享库加载到 Java 代码中,则它们需要与 JVM 相同的架构)。 - pevik
4
经过一番研究,我决定使用这个方法。但我很好奇,在这台机器上(Windows 8.1 64位系统),环境变量ProgramFiles(x86)没有列在“This PC” / 属性/高级系统设置/环境变量下,然而System.getenv("ProgramFiles(x86)")确实返回值C:\Program Files (x86),这当然很好,因为看起来这样的变量不能被用户修改或删除;是这样吗? ProgramFiles(x86)是某种“内部”的环境变量吗?答案:+1 经过相当多的研究,我将使用此方法。但我很好奇,对于这台机器(Windows 8.1 64位),环境变量ProgramFiles(x86)未列在“This PC” / 属性/高级系统设置/环境变量中,但是System.getenv("ProgramFiles(x86)")却可以返回值C:\Program Files (x86),这当然很好,因为看起来这个变量不能被用户修改或删除;是这样吗? ProgramFiles(x86)是一种“内部”的环境变量吗? - SantiBailors
1
这仍然不是完全可靠的,因为在生成进程之前可以擦除环境变量。更好的方法可能是检查 %Windir%\SysWOW64(表示 64 位进程)和 %Windir%\Sysnative(表示在 64 位 Windows 中运行的 32 位进程)的存在。 - phuclv

61

请注意,os.arch属性只会给出JRE的架构,而不是底层操作系统的架构。

如果在64位系统上安装了32位的jre,则System.getProperty("os.arch")将返回x86

为了实际确定底层架构,您需要编写一些本地代码。请参阅此文章获取更多信息(以及示例本地代码的链接)。


5

我使用命令提示符 (命令 --> wmic OS get OSArchitecture) 来获取操作系统架构。以下程序可以帮助获取所有必需的参数:

import java.io.*;

public class User {
    public static void main(String[] args) throws Exception {

        System.out.println("OS --> "+System.getProperty("os.name"));   //OS Name such as Windows/Linux

        System.out.println("JRE Architecture --> "+System.getProperty("sun.arch.data.model")+" bit.");       // JRE architecture i.e 64 bit or 32 bit JRE

        ProcessBuilder builder = new ProcessBuilder(
            "cmd.exe", "/c","wmic OS get OSArchitecture");
        builder.redirectErrorStream(true);
        Process p = builder.start();
        String result = getStringFromInputStream(p.getInputStream());

        if(result.contains("64"))
            System.out.println("OS Architecture --> is 64 bit");  //The OS Architecture
        else
            System.out.println("OS Architecture --> is 32 bit");

        }


    private static String getStringFromInputStream(InputStream is) {

        BufferedReader br = null;
        StringBuilder sb = new StringBuilder();

        String line;
        try {

            br = new BufferedReader(new InputStreamReader(is));
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return sb.toString();

    }

}

3

我想分享一下我的Java代码解决方案(一个类似的是本机代码)。

我想要补充一下James Van Huis先生的答案。由于属性os.arch System.getProperty("os.arch")返回JRE的位数,因此这实际上非常有用。从文章中可以看到:

在您的代码中,您首先需要检查IntPtr的大小,如果返回8,则正在运行64位操作系统。如果返回4,则运行32位应用程序,现在您需要知道是否在WOW64下运行。

因此,IntPtr大小检查与查看"os.arch"执行的相同检查相同。之后,您可以继续找出进程是在本机环境下运行还是在WOW64下运行。

这可以使用jna库(例如NativeLibrary)来完成,该库提供了所需的本机函数的使用。

//test the JRE here by checking the os.arch property
//go into the try block if JRE is 32bit
try {
    NativeLibrary kernel32Library = NativeLibrary.getInstance("kernel32");
    Function isWow64Function = kernel32Library.getFunction("IsWow64Process");

    WinNT.HANDLE hProcess = Kernel32.INSTANCE.GetCurrentProcess();
    IntByReference isWow64 = new IntByReference(0);
    Boolean returnType = false;
    Object[] inArgs = {
        hProcess,
        isWow64
    };
    if ((Boolean) isWow64Function.invoke(returnType.getClass(), inArgs))    {
        if (isWow64.getValue() == 1)    {
                //32bit JRE on x64OS
        }
    }
} catch (UnsatisfiedLinkError e) {  //thrown by getFunction

}

类似这样的代码也可能会起作用,但我建议使用第一种版本,因为我在x64和32位JRE上测试过,而且应该更加安全,因为以下代码实际上没有检查“IsWow64Process”函数是否存在。

这里我添加了一个JRE检查的示例,以便完整,尽管很容易找到。

Map<String, Integer> archMap = new HashMap<String, Integer>();
archMap.put("x86", 32);
archMap.put("i386", 32);
archMap.put("i486", 32);
archMap.put("i586", 32);
archMap.put("i686", 32);
archMap.put("x86_64", 64);
archMap.put("amd64", 64);
//archMap.put("powerpc", 3);
this.arch = archMap.get(SystemUtils.OS_ARCH);
if (this.arch == null)  {
    throw new IllegalArgumentException("Unknown architecture " + SystemUtils.OS_ARCH);
}

1

(仅适用于Windows) 检查 C:\Windows\SysWOW64 是否存在。如果该目录存在,则是64位进程。否则,它是32位进程。


0

你可以通过命令行获取“真实”的操作系统架构。 你可以使用“wmic cpu get AddressWidth”命令。

enter image description here

如果你想要处理器架构,可以使用"wmic cpu get DataWidth"。
我编写了一个简单的Java静态代码来尝试这个。
(免责声明:如果你想重用这段代码,你需要使用ProcessBuilder。)
public static String getOsArch() {
    String arch = null;
    try {
        arch = HotUtils.executeCmd("wmic cpu get AddressWidth");
        arch = arch.trim();
        arch = arch.replace("\n\n", "\n");
        arch = arch.replace(" ", "");
        arch = arch.trim();
        return arch.endsWith("64")? "64": "32";
    } catch (IOException ex) {
        Logger.getLogger(HotUtils.class.getName()).log(Level.SEVERE, null, ex);
    }
    return arch;
}

public static void main(String[] args) {
    System.out.println(HotUtils.getOsArch());
}

public static String executeCmd(String cmd) throws IOException {
    Runtime rt = Runtime.getRuntime();
    Process proc = rt.exec(cmd);

    BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream()));
    BufferedReader stdError = new BufferedReader(new InputStreamReader(proc.getErrorStream()));

    StringBuilder out = new StringBuilder();
    String s;
    while ((s = stdInput.readLine()) != null) {
        out.append(s);
    }

    while ((s = stdError.readLine()) != null) {
        out.append(s);
    }
    return out.toString();
}

为什么是-1?给我反馈,这是一种困难但有效的方法。 - Carlos Jesus Arancibia Taborga

0

也许这不是最好的方法,但它能够工作。

我所做的就是获取Windows为Program Files x86文件夹配置的"环境变量"。我的意思是,Windows x64有文件夹(Program Files x86),而x86没有。因为用户可以在"环境变量"中更改Program Files路径,或者他/她可能在C:\中创建一个名为"Program Files (x86)"的目录,所以我不会使用检测文件夹而是使用Windows注册表中"Program Files (x86)"的"环境路径"变量。

public class getSystemInfo {

    static void suckOsInfo(){

    // Get OS Name (Like: Windows 7, Windows 8, Windows XP, etc.)
    String osVersion = System.getProperty("os.name");
    System.out.print(osVersion);

    String pFilesX86 = System.getenv("ProgramFiles(X86)");
    if (pFilesX86 !=(null)){
        // Put here the code to execute when Windows x64 are Detected
    System.out.println(" 64bit");
    }
    else{
        // Put here the code to execute when Windows x32 are Detected
    System.out.println(" 32bit");
    }

    System.out.println("Now getSystemInfo class will EXIT");
    System.exit(0);

    }

}

嗯,用户Boolean已经用更好的代码以同样的方式实现了。 - Blackgeo32

0

你可以尝试这段代码,我认为检测JVM的型号会更好一些。

boolean is64bit = System.getProperty("sun.arch.data.model").contains("64");

3
OP询问的是操作系统(OS),而不是Java虚拟机(JVM)。 - leonbloy
无法工作,在Windows 10(64位)上使用32位Java 8进行了检查。 - Daniel
它可能起作用,也可能不起作用;在某些操作系统中,此键可能不存在。请查看 https://dev59.com/cnRA5IYBdhLWcg3w1BqW 的最受欢迎的答案。在我的Win10上,它是存在的。 - WesternGun

-3
System.getProperty("os.arch");

13
在我的64位Windows系统上,使用32位的Java虚拟机输出的是"x86"。因此,我猜测它显示的不是操作系统的版本,而是虚拟机的版本。 - Mirek Pluta

-5
你可以使用系统属性中的os.arch属性来查找。
Properties pr = System.getProperties();
System.out.println(pr.getProperty("os.arch"));

如果您使用的是32位系统,应该会显示i386或类似的内容。


2
在运行32位JVM的64位操作系统上,这将返回x86,表示32位。虽然对于JVM来说是正确的,但对于操作系统来说是错误的,这正是OP所问的。 - CMerrill

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