Qual è il modo migliore per trovare la home directory degli utenti in Java?


280

La difficoltà è che dovrebbe essere multipiattaforma. Windows 2000, XP, Vista, OSX, Linux, altre varianti unix. Sto cercando uno snippet di codice in grado di farlo per tutte le piattaforme e un modo per rilevare la piattaforma.

Ora, dovresti essere consapevole del bug 4787931 che user.homenon funziona correttamente, quindi per favore non fornirmi le risposte del libro di testo, posso trovarle da me nei manuali.


1
Hai provato le soluzioni alternative menzionate nel bug? Ci sono molti suggerimenti.
Joachim Sauer,

1
il bug 4787931 per le versioni java fino alla 1.4.2 viene nuovamente visualizzato come bug 6519127 per java 1.6. Il problema non sta scomparendo ed è ancora elencato come priorità bassa.
GregA100k,

16
Nota: il bug 4787391 è contrassegnato come corretto in Java 8
Steven R. Loomis,

Risposte:


366

Il bug a cui si fa riferimento (bug 4787391) è stato corretto in Java 8. Anche se si utilizza una versione precedente di Java, l' System.getProperty("user.home")approccio è probabilmente il migliore. L' user.homeapproccio sembra funzionare in un numero molto elevato di casi. Una soluzione al 100% a prova di proiettile su Windows è difficile, perché Windows ha un concetto mutevole di cosa significhi la directory home.

Se user.homenon è abbastanza buono per te, suggerirei di scegliere una definizione di home directoryper Windows e di usarla, ottenendo la variabile d'ambiente appropriata con System.getenv(String).


136

In realtà con Java 8 il modo giusto è usare:

System.getProperty("user.home");

Il bug JDK-6519127 è stato corretto e la sezione "Incompatibilità tra JDK 8 e JDK 7" delle note di rilascio indica:

Area: Core Libs / java.lang

Sinossi

I passaggi utilizzati per determinare la home directory dell'utente su Windows sono stati modificati per seguire l'approccio consigliato da Microsoft. Questa modifica potrebbe essere osservabile su edizioni precedenti di Windows o in cui le impostazioni del registro o le variabili di ambiente sono impostate su altre directory. Natura dell'incompatibilità

behavioral RFE

6519127

Nonostante la domanda sia vecchia, la lascio come riferimento futuro.


35
System.getProperty("user.home");

Vedi JavaDoc .


11
No, non è una risposta corretta, questa è la stessa di cui sopra. Sì, non solo ho letto JavaDocs, ma l'ho provato anche su tutte le piattaforme prima di porre questa domanda! La risposta non è così semplice
Bruno Ranschaert,

3
Questo potrebbe andare terribilmente storto su Windows, dove ci vorrà solo il genitore della directory desktop, che potrebbe trovarsi ovunque ...
Chronial,

29

Il concetto di una directory HOME sembra essere un po 'vago quando si tratta di Windows. Se le variabili di ambiente (HOMEDRIVE / HOMEPATH / USERPROFILE) non sono sufficienti, potrebbe essere necessario ricorrere all'uso di funzioni native tramite JNI o JNA . SHGetFolderPath ti consente di recuperare cartelle speciali, come Documenti (CSIDL_PERSONAL) o Impostazioni locali \ Dati applicazioni (CSIDL_LOCAL_APPDATA).

Codice JNA di esempio:

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);

    }

}

Cordiali saluti, la cartella che corrisponde alla home directory dell'utente è CSIDL_PROFILE. Vedere msdn.microsoft.com/en-us/library/bb762494(VS.85).aspx .
Matt Solnit,

Sì, questa è una versione elaborata per il caso Windows.
Bruno Ranschaert,

2
Nelle versioni recenti di JNA (più precisamente jna-platform), esiste una classe Shell32Util che incapsula l'API di Windows corrispondente in un modo molto carino. In particolare, l'utilizzo di Shell32Util.getKnownFolderPath (...) in combinazione con una delle costanti della classe KnownFolders dovrebbe essere appropriato. La vecchia funzione API getFolderPath è obsoleta da Windows Vista.
Sebastian Marsching,

17

Altri hanno risposto alla mia domanda, ma un utile programma per stampare tutte le proprietà disponibili è:

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

Non dipenderei da questo, perché non tutte le proprietà sono standardizzate. Controlla invece JavaDoc per System.getProperties () per scoprire quali proprietà sono garantite.
Joachim Sauer,

6
Questo può essere vero, ma è ancora abbastanza utile per un principiante, penso! Non sono sicuro che meriti 2 downvotes :-(
oxbow_lakes,

6

Mentre stavo cercando la versione Scala, tutto quello che ho potuto trovare era il codice JNA di McDowell sopra. Includo qui la mia porta Scala, poiché attualmente non esiste un posto più appropriato.

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

Come con la versione Java, sarà necessario aggiungere Java Native Access , inclusi entrambi i file jar, alle librerie di riferimento.

È bello vedere che JNA ora lo rende molto più semplice rispetto a quando è stato pubblicato il codice originale.


2

Vorrei utilizzare l'algoritmo dettagliato nella segnalazione di bug utilizzando System.getenv (String) e fallback per utilizzare la proprietà user.dir se nessuna delle variabili di ambiente indicava una directory esistente valida. Questo dovrebbe funzionare multipiattaforma.

Penso che, sotto Windows, quello che cerchi davvero sia la directory "documenti" nozionale dell'utente.


2

Alternativa sarebbe usare Apache CommonsIO FileUtils.getUserDirectory()invece di System.getProperty("user.home"). Otterrà lo stesso risultato e non è possibile introdurre un refuso quando si specifica la proprietà di sistema.

C'è una grande possibilità che tu abbia già la libreria Apache CommonsIO nel tuo progetto. Non presentarlo se prevedi di utilizzarlo solo per ottenere la home directory dell'utente.


0

Se vuoi qualcosa che funzioni bene su Windows c'è un pacchetto chiamato WinFoldersJava che avvolge la chiamata nativa per ottenere le directory 'speciali' su Windows. Lo usiamo spesso e funziona bene.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.