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

Bru*_*ert 255 java cross-platform home-directory

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

现在,你应该知道的错误4787931user.home不能正常工作,所以请不要为我提供教科书的答案,我可以在手册中找到这些我自己.

DJC*_*rth 334

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

如果user.home对你不够好,我会建议选择home directoryWindows 的定义并使用它,获取适当的环境变量System.getenv(String).

  • Apache 有一个 [优秀的包装器](http://commons.apache.org/proper/commons-lang/javadocs/api-release/org/apache/commons/lang3/SystemUtils.html) 用于 `System.getProperty` 调用我推荐使用。正确的调用是“SystemUtils.getUserHome()”。 (3认同)

Pau*_*lgo 123

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

System.getProperty("user.home");
Run Code Online (Sandbox Code Playgroud)

错误JDK-6519127已修复,发行说明中的 "JDK 8和JDK 7之间的不兼容性"部分指出:

区域:Core Libs/java.lang

概要

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

behavioral RFE

6519127
Run Code Online (Sandbox Code Playgroud)

尽管问题很老,但我还是留待将来参考.


Joa*_*uer 32

System.getProperty("user.home");
Run Code Online (Sandbox Code Playgroud)

请参阅JavaDoc.

  • 不,不是正确的答案,这与上面的相同.是的,我不仅阅读了JavaDocs,而且在提出这个问题之前我也在所有平台上试过了!答案并非如此简单. (9认同)
  • 这可能在Windows上出现了可怕的错误,它只会占用桌面目录的父级,这可能是任何地方...... (3认同)

McD*_*ell 28

对于Windows而言,HOME目录的概念似乎有点模糊.如果环境变量(HOMEDRIVE/HOMEPATH/USERPROFILE)不够,则可能不得不求助于通过JNIJNA使用本机函数.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);

    }

}
Run Code Online (Sandbox Code Playgroud)

  • 在最新版本的JNA(更确切地说是jna平台)中,有一个Shell32Util类,它以一种非常不错的方式封装了相应的Windows API。特别是,将Shell32Util.getKnownFolderPath(...)与KnownFolders类的常量之一结合使用是合适的。从Windows Vista开始,不再使用较早的getFolderPath API函数。 (2认同)

oxb*_*kes 17

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

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

  • 这可能是真的,但对于我认为的新手来说它仍然非常有用!我不确定它应该得到2个downvotes :-( (6认同)

mla*_*dzo 6

替代方法是使用 Apache CommonsIOFileUtils.getUserDirectory()而不是System.getProperty("user.home"). 它会给你相同的结果,并且在指定系统属性时没有机会引入拼写错误。

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


小智 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")
            })
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

很高兴看到,与发布原始代码相比,JNA现在使此操作变得容易得多。