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

发布于 2024-07-13 18:14:10 字数 365 浏览 5 评论 0原文

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

困难在于解决方案应该是跨平台的; 它应该可以在 Windows 2000、XP、Vista、OS X、Linux 和其他 Unix 变体上运行。 我正在寻找可以在所有平台上完成此操作的代码片段,以及检测平台的方法。

每个 Java bug 4787931,系统属性 user.home 在 Windows XP 上无法正常工作,因此使用此系统属性不是可接受的解决方案,因为它不是跨平台的。

What is the best way to find the user's home directory in Java?

The difficulty is that the solution should be cross-platform; it should work on Windows 2000, XP, Vista, OS X, Linux, and other Unix variants. I am looking for a snippet of code that can accomplish this for all platforms, and a way to detect the platform.

Per Java bug 4787931, system property user.home does not work correctly on Windows XP, so using this system property is not an acceptable solution as it is not cross-platform.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

王权女流氓 2024-07-20 18:14:11

您引用的错误(错误 4787391)已在 Java 8 中修复。即使您使用旧版本的 Java,System.getProperty("user.home") 方法可能仍然是最好的。 user.home 方法似乎在很多情况下都有效。 在 Windows 上实现 100% 无懈可击的解决方案很困难,因为 Windows 对主目录含义的概念发生了变化。

如果 user.home 对您来说不够好,我建议为 Windows 选择一个 home 目录 的定义并使用它,通过 System 获取适当的环境变量.getenv(字符串)

The bug you reference (bug 4787391) has been fixed in Java 8. Even if you are using an older version of Java, the System.getProperty("user.home") approach is probably still the best. The user.home approach seems to work in a very large number of cases. A 100% bulletproof solution on Windows is hard, because Windows has a shifting concept of what the home directory means.

If user.home isn't good enough for you I would suggest choosing a definition of home directory for windows and using it, getting the appropriate environment variable with System.getenv(String).

刘备忘录 2024-07-20 18:14:11

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

System.getProperty("user.home");

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

区域:核心库/java.lang

剧情简介

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

行为 RFE 

  6519127 
  

尽管这个问题很老,但我还是将其保留以供将来参考

Actually with Java 8 the right way is to use:

System.getProperty("user.home");

The bug JDK-6519127 has been fixed and the "Incompatibilities between JDK 8 and JDK 7" section of the release notes states:

Area: Core Libs / java.lang

Synopsis

The steps used to determine the user's home directory on Windows have changed to follow the Microsoft recommended approach. This change
might be observable on older editions of Windows or where registry
settings or environment variables are set to other directories. Nature
of Incompatibility

behavioral RFE

6519127

Despite the question being old I leave this for future reference.

錯遇了你 2024-07-20 18:14:11
System.getProperty("user.home");

请参阅 JavaDoc

System.getProperty("user.home");

See the JavaDoc.

电影里的梦 2024-07-20 18:14:11

对于 Windows 来说,HOME 目录的概念似乎有点模糊。 如果环境变量 (HOMEDRIVE/HOMEPATH/ USERPROFILE) 还不够,您可能必须通过 JNIJNASHGetFolderPath 允许您检索特殊文件夹,例如 < em>我的文档 (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);

    }

}

The concept of a HOME directory seems to be a bit vague when it comes to Windows. If the environment variables (HOMEDRIVE/HOMEPATH/USERPROFILE) aren't enough, you may have to resort to using native functions via JNI or JNA. SHGetFolderPath allows you to retrieve special folders, like My Documents (CSIDL_PERSONAL) or Local Settings\Application Data (CSIDL_LOCAL_APPDATA).

Sample JNA code:

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);

    }

}
江湖正好 2024-07-20 18:14:11

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

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

Others have answered the question before me but a useful program to print out all available properties is:

for (Map.Entry<?,?> e : System.getProperties().entrySet()) {
    System.out.println(String.format("%s = %s", e.getKey(), e.getValue())); 
}
囚你心 2024-07-20 18:14:11

另一种方法是使用 Apache CommonsIO FileUtils.getUserDirectory() 而不是 System.getProperty("user.home")。 它会得到相同的结果,并且在指定系统属性时不会出现拼写错误。

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

Alternative would be to use Apache CommonsIO FileUtils.getUserDirectory() instead of System.getProperty("user.home"). It will get you the same result and there is no chance to introduce a typo when specifying system property.

There is a big chance you already have Apache CommonsIO library in your project. Don't introduce it if you plan to use it only for getting user home directory.

柳絮泡泡 2024-07-20 18:14:11

当我搜索 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 添加到您引用的图书馆。

很高兴看到 JNA 现在使这比发布原始代码时容易得多。

As I was searching for Scala version, all I could find was McDowell's JNA code above. I include my Scala port here, as there currently isn't anywhere more appropriate.

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")
            })
        }
    }
}

As with the Java version, you will need to add Java Native Access, including both jar files, to your referenced libraries.

It's nice to see that JNA now makes this much easier than when the original code was posted.

比忠 2024-07-20 18:14:11

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

我认为,在Windows下,你真正想要的是用户名义上的“文档”目录。

I would use the algorithm detailed in the bug report using System.getenv(String), and fallback to using the user.dir property if none of the environment variables indicated a valid existing directory. This should work cross-platform.

I think, under Windows, what you are really after is the user's notional "documents" directory.

天涯沦落人 2024-07-20 18:14:11

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

If you want something that works well on windows there is a package called WinFoldersJava which wraps the native call to get the 'special' directories on Windows. We use it frequently and it works well.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文