Каков наилучший способ найти домашний каталог пользователей в Java?

StackOverflow https://stackoverflow.com/questions/585534

Вопрос

Трудность в том, что она должна быть кроссплатформенной.Windows 2000, XP, Vista, OSX, Linux, другие варианты unix.Я ищу фрагмент кода, который может выполнить это для всех платформ, и способ определения платформы.

Теперь вы должны быть осведомлены о ошибка 4787931 это user.home работает некорректно, поэтому, пожалуйста, не предоставляйте мне ответы из учебников, я сам могу найти их в руководствах.

Это было полезно?

Решение

Ошибка, на которую вы ссылаетесь (bug 4787391), была исправлена в Java 8.Даже если вы используете более старую версию Java, System.getProperty("user.home") подход, вероятно, по-прежнему является лучшим.В user.home подход, по-видимому, работает в очень большом количестве случаев.Создать 100% пуленепробиваемое решение в Windows сложно, потому что в Windows меняется представление о том, что означает домашний каталог.

Если user.home недостаточно хорош для вас, я бы предложил выбрать определение home directory для Windows и используя его, получая соответствующую переменную среды с System.getenv(String).

Другие советы

На самом деле с Java 8 правильный способ - использовать:

System.getProperty("user.home");

Ошибка JDK-6519127 был исправлен и раздел "Несовместимости между JDK 8 и JDK 7" в примечания к выпуску состояния:

Площадь:Основные библиотеки / java.lang

Краткий обзор

Шаги, используемые для определения домашнего каталога пользователя в Windows, были изменены в соответствии с подходом, рекомендованным Корпорацией Майкрософт.Это изменение может наблюдаться в старых версиях Windows или в реестре where параметры или переменные среды установлены в другие каталоги.Природа несовместимости

behavioral RFE

6519127

Несмотря на то, что вопрос старый, я оставляю это для дальнейшего использования.

System.getProperty("user.home");

Смотрите на Javadoc.

Концепция ДОМАШНЕГО каталога кажется немного расплывчатой, когда речь заходит о Windows.Если в переменные среды (HOMEDRIVE / HOMEPATH /USERPROFILE) недостаточно, возможно, вам придется прибегнуть к использованию встроенных функций через ДЖНИ или ЮНА. 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())); 
}

Поскольку я искал версию 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, включая оба файла jar, в ваши библиотеки, на которые даны ссылки.

Приятно видеть, что JNA теперь делает это намного проще, чем когда был опубликован исходный код.

Я бы использовал алгоритм, подробно описанный в отчете об ошибке, используя System.getenv(String), и вернулся бы к использованию свойства user.dir, если ни одна из переменных среды не указала действительный существующий каталог.Это должно работать кроссплатформенно.

Я думаю, что в Windows то, что вам действительно нужно, - это условный каталог пользователя "documents".

Если вам нужно что-то, что хорошо работает в Windows, есть пакет под названием WinFoldersJava Винфолдерсджава который обертывает собственный вызов для получения "специальных" каталогов в Windows.Мы часто используем его, и он хорошо работает.

Альтернативой было бы использовать Apache CommonsIO FileUtils.getUserDirectory() вместо того , чтобы System.getProperty("user.home").Это даст вам тот же результат, и нет никакой возможности допустить опечатку при указании системного свойства.

Существует большая вероятность, что у вас уже есть библиотека Apache CommonsIO в вашем проекте.Не вводите его, если вы планируете использовать его только для получения домашнего каталога пользователя.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top