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

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

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

您引用的bug(bug 4787391)已经在Java 8中修复了。即使您使用的是较旧版本的Java, System.getProperty("user.home")方法仍可能是最好的。 user.home方法似乎在很多情况下工作。 Windows上的100%防弹解决scheme很难,因为Windows对主目录的含义有一个转变的概念。

如果user.home对你来说不够好,我build议你select一个windows home directory的定义并使用它,用System.getenv(String)获取适当的环境variables。

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

 System.getProperty("user.home"); 

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

区域:核心库/ java.lang

概要

用于在Windows上确定用户主目录的步骤已更改为遵循Microsoft推荐的方法。 在较早的Windows版本上,或者将registry设置或环境variables设置为其他目录时,可能会观察到此更改。 不相容的性质

 behavioral RFE 6519127 

尽pipe这个问题很老,我留待以后参考。

当涉及到Windows时,HOME目录的概念似乎有些模糊。 如果环境variables (HOMEDRIVE / HOMEPATH / USERPROFILE)不够用,可能需要通过JNI或JNA使用原生函数。 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); } } 
 System.getProperty("user.home"); 

请参阅JavaDoc 。

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

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

当我在寻找Scala版本时,我能find的就是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现在比原始代码发布更容易。

如果没有环境variables指示有效的现有目录,则使用System.getenv(String)在缺陷报告中详细描述的algorithm,并使用user.dir属性。 这应该跨平台工作。

我认为,在Windows下,你实际上是用户的名义“文件”目录。

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