在Java中查找用户主目录的最佳方法是什么?
难点在于解决方案应该是跨平台的;它应该可以在Windows 2000、XP、Vista、OS X、Linux和其他Unix变体上运行。我正在寻找一个代码片段,可以为所有平台完成这一点,以及一种检测平台的方法。
每个Java错误4787931,系统属性用户。home在Windows XP上不能正常工作,因此使用这个系统属性不是一个可接受的解决方案,因为它不是跨平台的。
在Java中查找用户主目录的最佳方法是什么?
难点在于解决方案应该是跨平台的;它应该可以在Windows 2000、XP、Vista、OS X、Linux和其他Unix变体上运行。我正在寻找一个代码片段,可以为所有平台完成这一点,以及一种检测平台的方法。
每个Java错误4787931,系统属性用户。home在Windows XP上不能正常工作,因此使用这个系统属性不是一个可接受的解决方案,因为它不是跨平台的。
当前回答
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).
其他回答
当我在搜索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(包括两个jar文件)添加到您所引用的库中。
很高兴看到JNA现在比发布原始代码时更容易做到这一点。
如果你想在windows上工作得很好,有一个叫做WinFoldersJava的包,它包装了本机调用来获得windows上的“特殊”目录。我们经常使用它,而且效果很好。
System.getProperty("user.home");
参见JavaDoc。
替代方案是使用Apache CommonsIO FileUtils.getUserDirectory()而不是System.getProperty("user.home")。它将得到相同的结果,并且在指定系统属性时不会出现输入错误。
您的项目中很有可能已经有Apache CommonsIO库。如果你计划只用它来获取用户主目录,就不要引入它。
当涉及到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);
}
}