在Java中查找用户主目录的最佳方法是什么?
难点在于解决方案应该是跨平台的;它应该在Windows 2000、XP、Vista、OS X、Linux和其他Unix变体上工作。我正在寻找一段代码片段,可以为所有平台完成此操作,并且需要一种检测平台的方法。
根据Java bug 4787931,系统属性user.home
在Windows XP上无法正常工作,因此使用此系统属性不是可接受的解决方案,因为它不是跨平台的。
在Java中查找用户主目录的最佳方法是什么?
难点在于解决方案应该是跨平台的;它应该在Windows 2000、XP、Vista、OS X、Linux和其他Unix变体上工作。我正在寻找一段代码片段,可以为所有平台完成此操作,并且需要一种检测平台的方法。
根据Java bug 4787931,系统属性user.home
在Windows XP上无法正常工作,因此使用此系统属性不是可接受的解决方案,因为它不是跨平台的。
你提到的漏洞(bug 4787391)已经在Java 8中修复。即使您正在使用旧版本的Java,System.getProperty("user.home")
方法可能仍然是最佳选择。在许多情况下,user.home
方法似乎是有效的。在Windows上,100%完美的解决方案很难实现,因为Windows对“主目录”的定义是不断变化的。
如果user.home
不能满足您的需求,我建议为Windows选择一个“主目录”定义,并使用System.getenv(String)
获取适当的环境变量。
System.getProperty
调用,我建议使用它。在该包装器下正确的调用应该是SystemUtils.getUserHome()
。 - Varun Mathur实际上,使用Java 8的正确方法是:
System.getProperty("user.home");
漏洞JDK-6519127已经修复,版本说明中的“JDK 8和JDK 7之间的不兼容性”部分说明:
领域:核心库 / java.lang
简介
用于在Windows上确定用户主目录的步骤已更改为遵循Microsoft推荐的方法。此更改可能在旧版Windows或设置了其他目录的注册表设置或环境变量的情况下可观察到。不兼容性质
behavioral RFE
6519127
尽管这个问题很旧,我把它留下来供以后参考。System.getProperty("user.home");
请查看JavaDoc。
在Windows中,HOME目录的概念似乎有点模糊。如果环境变量(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);
}
}
虽然之前已经有人回答了这个问题,但是一个有用的程序可以打印出所有可用的属性:
for (Map.Entry<?,?> e : System.getProperties().entrySet()) {
System.out.println(String.format("%s = %s", e.getKey(), e.getValue()));
}
另一种选择是使用Apache CommonsIO FileUtils.getUserDirectory()
而不是System.getProperty("user.home")
。 它将为您提供相同的结果,并且在指定系统属性时没有引入输错的机会。
很有可能您已经在项目中使用了Apache CommonsIO库。 如果您计划仅用于获取用户主目录,请勿引入它。
File FileUtils.getUserDirectory()
| String FileUtils.getUserDirectoryPath()
- https://commons.apache.org/proper/commons-io/apidocs/org/apache/commons/io/FileUtils.htmlFile FileUtils.getUserDirectory()
返回当前用户的主目录作为文件对象。String FileUtils.getUserDirectoryPath()
返回当前用户的主目录路径作为字符串。 详见:https://commons.apache.org/proper/commons-io/apidocs/org/apache/commons/io/FileUtils.html - Pang当我在寻找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")
})
}
}
}