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

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

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

根据Java错误4787931,系统属性user.home在Windows XP上不能正确工作,因此使用这个系统属性不是一个可接受的解决方案,因为它不是跨平台的。

302296 次浏览
System.getProperty("user.home");

参见JavaDoc

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

for (Map.Entry<?,?> e : System.getProperties().entrySet()) {
System.out.println(String.format("%s = %s", e.getKey(), e.getValue()));
}
你所引用的错误(bug 4787391)在Java 8中已被修复。即使你使用的是旧版本的Java, System.getProperty("user.home")方法可能仍然是最好的。user.home方法似乎在很多情况下都有效。在Windows上100%防弹的解决方案是困难的,因为Windows对主目录的含义有一个不断变化的概念 如果user.home对你来说不够好,我建议为windows选择一个home directory的定义并使用它,使用System.getenv(String)获得适当的环境变量

当涉及到Windows时,HOME目录的概念似乎有点模糊。如果环境变量 (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);


}


}

我会使用bug报告中详细描述的算法System.getenv(String),然后退回到使用用户。如果没有任何环境变量指示有效的现有目录,则使用Dir属性。这应该是跨平台的。

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

当我在搜索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本机访问(包括两个jar文件)添加到您引用的库中。

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

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

System.getProperty("user.home");

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

业务范围:Core Libs / java.lang

剧情简介

用于确定Windows上用户的主目录的步骤已更改为遵循微软推荐的方法。这种变化 可能在旧版本的Windows或where registry上可见 将设置或环境变量设置到其他目录。自然 不相容的< / p >
behavioral RFE


6519127

尽管这个问题已经很老了,我还是把它留给以后的参考。

如果你想让某些东西在windows上工作得很好,有一个名为WinFoldersJava的包,它包装本机调用以获取windows上的“特殊”目录。我们经常使用它,而且效果很好。

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

您的项目中很有可能已经有Apache CommonsIO库。如果你计划只用它来获取用户主目录,就不要引入它。