在 Java 中查找用户主目录的最佳方法是啥?

Posted

技术标签:

【中文标题】在 Java 中查找用户主目录的最佳方法是啥?【英文标题】:What is the best way to find the user's home directory in Java?在 Java 中查找用户主目录的最佳方法是什么? 【发布时间】:2010-10-09 18:57:11 【问题描述】:

困难在于它应该是跨平台的。 Windows 2000、XP、Vista、OSX、Linux、其他 unix 变体。我正在寻找可以在所有平台上完成此操作的 sn-p 代码,以及检测平台的方法。

现在,您应该知道bug 4787931 user.home 无法正常工作,所以请不要向我提供教科书式的答案,我自己可以在手册中找到这些答案。

【问题讨论】:

您是否尝试过错误中提到的解决方法?有很多建议。 1.4.2 以上的 java 版本的错误 4787931 再次显示为 java 1.6 的错误 6519127。问题并没有消失,仍然被列为低优先级。 注意:错误 4787391 在 Java 8 中被标记为已修复 【参考方案1】:

替代方案是使用 Apache CommonsIO FileUtils.getUserDirectory() 而不是 System.getProperty("user.home")。它会得到相同的结果,并且在指定系统属性时不会引入错字。

您的项目中很有可能已经拥有 Apache CommonsIO 库。如果您打算仅将其用于获取用户主目录,请不要引入它。

【讨论】:

File FileUtils.getUserDirectory() | String FileUtils.getUserDirectoryPath() - commons.apache.org/proper/commons-io/apidocs/org/apache/commons/…【参考方案2】:

如果您想要在 Windows 上运行良好的东西,有一个名为 WinFoldersJava 的包,它包装了本机调用以获取 Windows 上的“特殊”目录。我们经常使用它,而且效果很好。

【讨论】:

答案中的链接已失效 - "404 | 这不是您要查找的网页"【参考方案3】:

您引用的错误(错误 4787391)已在 Java 8 中修复。即使您使用的是旧版本的 Java,System.getProperty("user.home") 方法可能仍然是最好的。 user.home 方法似乎在很多情况下都有效。 Windows 上的 100% 防弹解决方案很难,因为 Windows 对主目录的含义有一个不断变化的概念。 如果 user.home 对你来说不够好,我建议为 windows 选择 home directory 的定义并使用它,使用 System.getenv(String) 获取适当的环境变量。

【讨论】:

Apache 有一个 excellent wrapper 用于我推荐使用的 System.getProperty 调用。正确的调用是SystemUtils.getUserHome()【参考方案4】:

其实用 Java 8 正确的方法是使用:

System.getProperty("user.home");

错误 JDK-6519127 已修复,release notes 的“JDK 8 和 JDK 7 之间的不兼容性”部分指出:

区域:核心库/java.lang

概要

用于在 Windows 上确定用户主目录的步骤已更改为遵循 Microsoft 推荐的方法。这种变化 可能在旧版本的 Windows 或注册表中可以观察到 设置或环境变量设置为其他目录。自然 不兼容

behavioral RFE

6519127

尽管这个问题很老,但我将其留作将来参考。

【讨论】:

【参考方案5】:

当我在搜索 Scala 版本时,我只能找到上面 McDowell 的 JNA 代码。我在这里包括我的 Scala 端口,因为目前没有更合适的地方。

import com.sun.jna.platform.win32._
object jna 
    def getHome: java.io.File = 
        if (!com.sun.jna.Platform.isWindows()) 
            new java.io.File(System.getProperty("user.home"))
        
        else 
            val pszPath: Array[Char] = new Array[Char](WinDef.MAX_PATH)
            new java.io.File(Shell32.INSTANCE.SHGetSpecialFolderPath(null, pszPath, ShlObj.CSIDL_MYDOCUMENTS, false) match 
                case true => new String(pszPath.takeWhile(c => c != '\0'))
                case _    => System.getProperty("user.home")
            )
        
    

与 Java 版本一样,您需要将 Java Native Access(包括两个 jar 文件)添加到您引用的库中。

很高兴看到 JNA 现在比发布原始代码时更容易做到这一点。

【讨论】:

【参考方案6】:

我会使用错误报告中详述的算法,使用 System.getenv(String),如果没有环境变量指示有效的现有目录,则回退到使用 user.dir 属性。这应该可以跨平台工作。

我认为,在 Windows 下,您真正​​追求的是用户名义上的“文档”目录。

【讨论】:

【参考方案7】:

对于 Windows,HOME 目录的概念似乎有点模糊。如果environment variables (HOMEDRIVE/HOMEPATH/USERPROFILE) 还不够,您可能不得不通过JNI 或JNA 使用本机函数。 SHGetFolderPath 允许您检索特殊文件夹,例如 My Documents (CSIDL_PERSONAL) 或 Local Settings\Application Data (CSIDL_LOCAL_APPDATA)。

示例 JNA 代码:

public class PrintAppDataDir 

    public static void main(String[] args) 
        if (com.sun.jna.Platform.isWindows()) 
            HWND hwndOwner = null;
            int nFolder = Shell32.CSIDL_LOCAL_APPDATA;
            HANDLE hToken = null;
            int dwFlags = Shell32.SHGFP_TYPE_CURRENT;
            char[] pszPath = new char[Shell32.MAX_PATH];
            int hResult = Shell32.INSTANCE.SHGetFolderPath(hwndOwner, nFolder,
                    hToken, dwFlags, pszPath);
            if (Shell32.S_OK == hResult) 
                String path = new String(pszPath);
                int len = path.indexOf('\0');
                path = path.substring(0, len);
                System.out.println(path);
             else 
                System.err.println("Error: " + hResult);
            
        
    

    private static Map<String, Object> OPTIONS = new HashMap<String, Object>();
    static 
        OPTIONS.put(Library.OPTION_TYPE_MAPPER, W32APITypeMapper.UNICODE);
        OPTIONS.put(Library.OPTION_FUNCTION_MAPPER,
                W32APIFunctionMapper.UNICODE);
    

    static class HANDLE extends PointerType implements NativeMapped 
    

    static class HWND extends HANDLE 
    

    static interface Shell32 extends Library 

        public static final int MAX_PATH = 260;
        public static final int CSIDL_LOCAL_APPDATA = 0x001c;
        public static final int SHGFP_TYPE_CURRENT = 0;
        public static final int SHGFP_TYPE_DEFAULT = 1;
        public static final int S_OK = 0;

        static Shell32 INSTANCE = (Shell32) Native.loadLibrary("shell32",
                Shell32.class, OPTIONS);

        /**
         * see http://msdn.microsoft.com/en-us/library/bb762181(VS.85).aspx
         * 
         * HRESULT SHGetFolderPath( HWND hwndOwner, int nFolder, HANDLE hToken,
         * DWORD dwFlags, LPTSTR pszPath);
         */
        public int SHGetFolderPath(HWND hwndOwner, int nFolder, HANDLE hToken,
                int dwFlags, char[] pszPath);

    


【讨论】:

仅供参考,对应于用户主目录的文件夹是 CSIDL_PROFILE。见msdn.microsoft.com/en-us/library/bb762494(VS.85).aspx。 是的,这是针对 Windows 机箱的精心制作的版本。 在最新版本的 JNA(更准确地说是 jna-platform)中,有一个 Shell32Util 类以非常好的方式封装了相应的 Windows API。特别是,将 Shell32Util.getKnownFolderPath(...) 与 KnownFolders 类中的常量之一结合使用应该是合适的。自 Windows Vista 以来,旧的 getFolderPath API 函数已被弃用。【参考方案8】:

其他人已经回答了我面前的问题,但打印出所有可用属性的有用程序是:

for (Map.Entry<?,?> e : System.getProperties().entrySet()) 
    System.out.println(String.format("%s = %s", e.getKey(), e.getValue())); 

【讨论】:

我不会依赖这个,因为并非所有属性都是标准化的。而是检查 JavaDoc 的 System.getProperties() 以找出保证存在的属性。 这可能是真的,但我认为它对于新手来说仍然非常有用!我不确定它是否值得 2 反对:-(【参考方案9】:
System.getProperty("user.home");

请参阅JavaDoc。

【讨论】:

不,不是正确答案,这和上面的一样。是的,在问这个问题之前,我不仅阅读了 JavaDocs,而且还在所有平台上进行了尝试!答案没那么简单。 这在 Windows 上可能会出现严重错误,它只会获取桌面目录的父目录,它可能在任何地方......

以上是关于在 Java 中查找用户主目录的最佳方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

在 Windows 窗体应用程序中查找长时间运行代码的最佳方法是啥

创建 whois 查找的最佳方法是啥? [关闭]

在其他地图值中查找元素的最佳方法是啥?

在 node.js 中的数组内查找字符串的最佳方法是啥?

在 Java 的并行线程中写入文件的最佳方法是啥?

在 iPhone 上构建“查找最近”位置感知应用程序的最佳方法是啥?