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

时间:2009-02-25 10:46:52

标签: java cross-platform home-directory

困难在于它应该是跨平台的。 Windows 2000,XP,Vista,OSX,Linux,其他unix版本。我正在寻找可以为所有平台实现此目的的代码片段,以及一种检测平台的方法。

现在,您应该知道user.home {{1}}无法正常工作,所以请不要向我提供教科书答案,我可以在手册中找到。

9 个答案:

答案 0 :(得分:312)

您引用的错误(错误4787391)已在Java 8中修复。即使您使用的是旧版本的Java,System.getProperty("user.home")方法仍可能是最佳方法。 user.home方法似乎适用于大量案例。 Windows上的100%防弹解决方案很难,因为Windows对主目录的含义有一个转变的概念。

如果user.home对您不够好,我建议为Windows选择home directory的定义并使用它,使用System.getenv(String)获取相应的环境变量。

答案 1 :(得分:115)

实际上,使用Java 8,正确的方法是使用:

System.getProperty("user.home");

错误 JDK-6519127已得到修复,JDK 8与JDK 7"之间的不兼容性已得到修复。 release notes州的一部分:

  

区域:Core Libs / java.lang

     

概要

     

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

behavioral RFE

6519127

尽管问题已经存在,但我将此留待将来参考。

答案 2 :(得分:29)

System.getProperty("user.home");

请参阅JavaDoc

答案 3 :(得分:28)

对于Windows而言,HOME目录的概念似乎有点模糊。如果environment variables(HOMEDRIVE / HOMEPATH / USERPROFILE)不够,则可能不得不通过JNIJNA使用本机函数。 SHGetFolderPath允许您检索特殊文件夹,例如我的文档(CSIDL_PERSONAL)或本地设置\应用程序数据(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);

    }

}

答案 4 :(得分:16)

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

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

答案 5 :(得分: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 :(得分:2)

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

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

答案 7 :(得分:0)

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

答案 8 :(得分:0)

替代方法是使用Apache CommonsIO FileUtils.getUserDirectory()代替System.getProperty("user.home")。指定系统属性时,它将获得相同的结果,并且没有机会引入错字。

您的项目中已经有Apache CommonsIO库的可能性很大。如果您打算仅将其用于获取用户主目录,请不要对其进行介绍。