如何通过Java获取Windows 10系统中已安装应用列表
我刚好遇到过类似的需求,要实现和你指定的PowerShell命令完全一致的结果,其实核心是要覆盖Windows注册表中两个关键的Uninstall路径——因为64位系统里,64位程序和32位程序的卸载信息分别存在不同的注册表位置。下面给你两种可靠的实现方式:
方法一:直接调用PowerShell命令(最省心,结果完全一致)
这种方式直接复用你已经验证过的PowerShell逻辑,不需要自己处理注册表的细节,能保证输出结果和Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | Select-Object DisplayName, DisplayVersion, Publisher,...完全匹配(我还补充了64位程序的注册表路径,让结果更完整)。
代码示例
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; public class InstalledAppsReader { public static void main(String[] args) { List<AppInfo> installedApps = getInstalledAppsViaPowerShell(); for (AppInfo app : installedApps) { System.out.printf("名称:%s,版本:%s,发布者:%s%n", app.displayName, app.displayVersion, app.publisher); } } private static List<AppInfo> getInstalledAppsViaPowerShell() { List<AppInfo> apps = new ArrayList<>(); // 完整的PowerShell命令,覆盖32位和64位程序的注册表路径,过滤掉无显示名称的项 String[] command = { "powershell.exe", "-Command", "Get-ItemProperty HKLM:\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*, " + "HKLM:\\Software\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\* | " + "Select-Object DisplayName, DisplayVersion, Publisher, InstallDate | " + "Where-Object { $_.DisplayName -ne $null } | ConvertTo-Json" }; try { Process process = new ProcessBuilder(command).start(); BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); StringBuilder jsonOutput = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { jsonOutput.append(line); } process.waitFor(); // 用Gson解析JSON输出(需要引入Gson依赖) Gson gson = new Gson(); apps = gson.fromJson(jsonOutput.toString(), new TypeToken<List<AppInfo>>(){}.getType()); } catch (IOException | InterruptedException e) { e.printStackTrace(); } return apps; } // 定义存储应用信息的实体类 static class AppInfo { String displayName; String displayVersion; String publisher; String installDate; } }
说明:
- 命令里添加了
HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*来覆盖64位程序的信息 - 用
Where-Object { $_.DisplayName -ne $null }过滤掉没有显示名称的系统组件项 - 最后用
ConvertTo-Json把输出转成JSON格式,配合Gson库可以轻松解析成Java对象
方法二:直接读取Windows注册表(更灵活,不依赖PowerShell)
如果你不想依赖PowerShell,可以用JNA库直接访问Windows注册表,这样能更灵活地控制读取逻辑。需要注意的是,Java标准库没有提供访问Windows注册表的API,所以需要引入JNA依赖。
步骤1:引入JNA依赖
如果用Maven,在pom.xml中添加:
<dependency> <groupId>net.java.dev.jna</groupId> <artifactId>jna</artifactId> <version>5.13.0</version> </dependency> <dependency> <groupId>net.java.dev.jna</groupId> <artifactId>jna-platform</artifactId> <version>5.13.0</version> </dependency>
步骤2:代码示例
import com.sun.jna.platform.win32.Advapi32Util; import com.sun.jna.platform.win32.WinReg; import java.util.ArrayList; import java.util.List; public class RegistryAppReader { private static final String[] REG_PATHS = { "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall", "Software\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall" }; public static void main(String[] args) { List<AppInfo> installedApps = getInstalledAppsFromRegistry(); for (AppInfo app : installedApps) { System.out.printf("名称:%s,版本:%s,发布者:%s%n", app.displayName, app.displayVersion, app.publisher); } } private static List<AppInfo> getInstalledAppsFromRegistry() { List<AppInfo> apps = new ArrayList<>(); for (String regPath : REG_PATHS) { try { // 读取注册表项,指定KEY_WOW64_64KEY确保在64位Java进程中能访问64位注册表 String[] subKeys = Advapi32Util.regEnumKey(WinReg.HKEY_LOCAL_MACHINE, regPath); for (String subKey : subKeys) { String fullPath = regPath + "\\" + subKey; try { String displayName = Advapi32Util.regGetStringValue(WinReg.HKEY_LOCAL_MACHINE, fullPath, "DisplayName"); if (displayName == null || displayName.isEmpty()) { continue; // 过滤无显示名称的项 } String displayVersion = Advapi32Util.regGetStringValue(WinReg.HKEY_LOCAL_MACHINE, fullPath, "DisplayVersion"); String publisher = Advapi32Util.regGetStringValue(WinReg.HKEY_LOCAL_MACHINE, fullPath, "Publisher"); String installDate = Advapi32Util.regGetStringValue(WinReg.HKEY_LOCAL_MACHINE, fullPath, "InstallDate"); AppInfo app = new AppInfo(); app.displayName = displayName; app.displayVersion = displayVersion; app.publisher = publisher; app.installDate = installDate; apps.add(app); } catch (Exception e) { // 有些注册表项可能没有某些属性,跳过即可 continue; } } } catch (Exception e) { // 如果某个注册表路径不存在(比如32位系统没有Wow6432Node),跳过 continue; } } return apps; } static class AppInfo { String displayName; String displayVersion; String publisher; String installDate; } }
为什么之前的win32库只返回部分结果?
大概率是因为只读取了其中一个注册表路径(比如只读取了Software\Microsoft\Windows\CurrentVersion\Uninstall而没读Wow6432Node下的路径),或者没有处理注册表的32位/64位视图——在64位系统中,64位程序和32位程序的卸载信息分别存在两个不同的注册表位置,必须同时读取才能得到完整列表。
内容的提问来源于stack exchange,提问作者Javier V. R.

