Как лучше всего найти домашний каталог пользователей на Java?
Сложность в том, что он должен быть кроссплатформенным. Windows 2000, XP, Vista, OSX, Linux, другие варианты unix. Я ищу фрагмент кода, который может сделать это для всех платформ, и способ обнаружения платформы.
Теперь вы должны знать об ошибке 4787931 , user.home
которая работает некорректно, поэтому, пожалуйста, не присылайте мне ответы из учебников, я сам найду их в руководствах.
Ответов (9)9
Ошибка, на которую вы ссылаетесь (ошибка 4787391), была исправлена в Java 8. Даже если вы используете старую версию Java, этот System.getProperty("user.home")
подход, вероятно, по-прежнему лучший. user.home
Похоже, что этот подход работает в очень большом количестве случаев. 100% пуленепробиваемое решение для Windows сложно, потому что в Windows меняются представления о том, что означает домашний каталог.
Если вам user.home
это не подходит, я бы предложил выбрать определение home directory
для Windows и использовать его, получив соответствующую переменную среды с помощью System.getenv(String)
.
Когда я искал версию Scala, все, что я смог найти, это приведенный выше код 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 делает это намного проще, чем когда был опубликован исходный код.
На самом деле с Java 8 правильный способ - использовать:
System.getProperty("user.home");
Ошибка JDK-6519127 была исправлена, а в разделе «Несовместимость между JDK 8 и JDK 7» примечаний к выпуску говорится:
Область: Core Libs / java.lang
Синопсис
Шаги, используемые для определения домашнего каталога пользователя в Windows, изменены в соответствии с подходом, рекомендованным Microsoft. Это изменение может наблюдаться в более старых выпусках Windows или в тех случаях, когда параметры реестра или переменные среды установлены для других каталогов. Природа несовместимости
behavioral RFE 6519127
Несмотря на то, что вопрос старый, я оставляю его на будущее.
Если вам нужно что-то, что хорошо работает в Windows, есть пакет WinFoldersJava, который обертывает собственный вызов для получения «специальных» каталогов в Windows. Мы используем его часто, и он хорошо работает.
Альтернативой было бы использование Apache CommonsIO FileUtils.getUserDirectory()
вместо System.getProperty("user.home")
. Это даст вам тот же результат, и при указании системного свойства нет возможности ввести опечатку.
Есть большая вероятность, что в вашем проекте уже есть библиотека Apache CommonsIO. Не вводите его, если вы планируете использовать его только для получения домашнего каталога пользователя.
System.getProperty("user.home");
См. JavaDoc .
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);
}
}
Я бы использовал алгоритм, описанный в отчете об ошибке, используя System.getenv (String), и отказался бы от использования свойства user.dir, если ни одна из переменных среды не указала действительный существующий каталог. Это должно работать на разных платформах.
Я думаю, что в Windows вам нужен каталог условных «документов» пользователя.