web-dev-qa-db-fra.com

Quel est le meilleur moyen de trouver le répertoire de base des utilisateurs en Java?

La difficulté est que cela devrait être multi-plateforme. Windows 2000, XP, Vista, OSX, Linux et autres variantes unix. Je suis à la recherche d'un extrait de code capable de le faire pour toutes les plateformes et d'un moyen de détecter la plateforme.

Maintenant, vous devriez savoir que le bogue 4787931 que user.home ne fonctionne pas correctement, veuillez donc ne pas me fournir de réponses textuelles, je peux les trouver moi-même dans les manuels.

218
Bruno Ranschaert

Le bogue que vous avez référencé (bogue 4787391) a été corrigé dans Java 8. Même si vous utilisez une version antérieure de Java, l’approche System.getProperty("user.home") est probablement toujours la meilleure. L’approche user.home semble fonctionner dans un très grand nombre de cas. Une solution à l'épreuve des balles à 100% sous Windows est difficile, car Windows a un concept changeant de la signification du répertoire personnel.

Si user.home n'est pas assez bon pour vous, je vous suggérerais de choisir une définition de home directory pour Windows et de l'utiliser pour obtenir la variable d'environnement appropriée avec System.getenv(String).

294
DJClayworth

En réalité, avec Java 8, le bon moyen consiste à utiliser:

System.getProperty("user.home");

Le bogue JDK-6519127 a été corrigé et la section "Incompatibilités entre JDK 8 et JDK 7" des notes de publication indique:

Zone: Core Libs/Java.lang

Synopsis

Les étapes utilisées pour déterminer le répertoire de base de l'utilisateur sous Windows ont été modifiées pour suivre l'approche recommandée par Microsoft. Ce changement peut être observé sur les anciennes éditions de Windows ou sur les registres les paramètres ou les variables d'environnement sont définis sur d'autres répertoires. La nature d'incompatibilité

behavioral RFE

6519127

Malgré la question étant vieux je laisse ceci pour la future référence.

111
Paulo Fidalgo

Le concept d'un répertoire HOME semble un peu vague en ce qui concerne Windows. Si les variables d'environnement (HOMEDRIVE/HOMEPATH/USERPROFILE) ne suffisent pas, vous devrez peut-être recourir aux fonctions natives via JNI ou JNA . SHGetFolderPath vous permet de récupérer des dossiers spéciaux, tels que Mes documents (CSIDL_PERSONAL) ou Local Settings\Application Data (CSIDL_LOCAL_APPDATA).

Exemple de code 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);

    }

}
27
McDowell
System.getProperty("user.home");

Voir le JavaDoc .

25
Joachim Sauer

D'autres ont répondu à la question avant moi, mais un programme utile pour imprimer toutes les propriétés disponibles est: 

for (Map.Entry<?,?> e : System.getProperties().entrySet()) {
    System.out.println(String.format("%s = %s", e.getKey(), e.getValue())); 
}
15
oxbow_lakes

Alors que je cherchais la version Scala, tout ce que je pouvais trouver était le code de la JNA de McDowell ci-dessus. J'inclus mon port Scala ici, car il n'y a actuellement aucun endroit plus approprié.

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")
            })
        }
    }
}

Comme pour la version Java, vous devrez ajouter Java Native Access , y compris les deux fichiers jar, à vos bibliothèques référencées.

Il est agréable de voir que la JNA rend maintenant cela beaucoup plus facile que lorsque le code original avait été publié.

4
Peter

J'utiliserais l'algorithme détaillé dans le rapport de bogue en utilisant System.getenv (String) et utiliserais la propriété user.dir si aucune des variables d'environnement n'indiquait un répertoire existant valide. Cela devrait fonctionner sur plusieurs plates-formes.

Je pense que, sous Windows, ce que vous recherchez réellement est le répertoire "documents" théorique de l'utilisateur.

2
Lawrence Dol

Si vous voulez quelque chose qui fonctionne bien sous Windows, il existe un paquetage appelé WinFoldersJava qui encapsule l'appel natif pour obtenir les répertoires "spéciaux" sous Windows. Nous l'utilisons fréquemment et cela fonctionne bien.

0
Neil Benn

L’autre solution serait d’utiliser Apache CommonsIO FileUtils.getUserDirectory() au lieu de System.getProperty("user.home"). Vous obtiendrez le même résultat et vous n'aurez aucune chance d'introduire une faute de frappe lors de la spécification de la propriété système.

Il y a de grandes chances que vous ayez déjà la bibliothèque Apache CommonsIO dans votre projet. Ne l'introduisez pas si vous envisagez de l'utiliser uniquement pour obtenir le répertoire de base de l'utilisateur.

0
mladzo