2009-02-25 6 views
182

Die Schwierigkeit ist, dass es plattformübergreifend sein sollte. Windows 2000, XP, Vista, OSX, Linux, andere Unix-Varianten. Ich suche nach einem Codeschnipsel, das dies für alle Plattformen erreichen kann, und nach einer Möglichkeit, die Plattform zu erkennen.Wie finde ich das Ausgangsverzeichnis des Benutzers in Java am besten?

Nun sollten Sie sich bewusst sein bug 4787931, dass user.home nicht richtig funktioniert, also bitte stellen Sie mir keine Lehrbuch Antworten, ich kann diese selbst in den Handbüchern finden.

+1

Haben Sie die im Fehler erwähnten Workarounds versucht? Es gibt viele Vorschläge. –

+1

Bug 4787931 für Java-Versionen bis 1.4.2 zeigt sich wieder als Bug 6519127 für Java 1.6. Das Problem verschwindet nicht und wird weiterhin als niedrig eingestuft. – GregA100k

+12

Hinweis: Fehler 4787391 ist in Java als behoben markiert 8 –

Antwort

240

Der Fehler, den Sie in Java festgelegt 8. Selbst Referenz (Bug 4787391) wurde, wenn Sie verwenden eine ältere Version von Java, der System.getProperty("user.home") Ansatz ist wahrscheinlich immer noch der beste. Der user.home Ansatz scheint in sehr vielen Fällen zu funktionieren. Eine 100% kugelsichere Lösung unter Windows ist schwierig, da Windows ein verändertes Konzept dessen hat, was das Home-Verzeichnis bedeutet.

Wenn user.home nicht gut genug für Sie ist, würde ich vorschlagen, eine Definition von home directory für Windows zu wählen und es zu verwenden, die passende Umgebungsvariable mit System.getenv(String) zu bekommen.

+2

Schließlich ist dies die beste Lösung schließlich. –

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

Siehe die JavaDoc.

+8

Nein, keine richtige Antwort, dies ist die gleiche wie oben. Ja, ich habe nicht nur die JavaDocs gelesen, sondern habe es auch auf allen Plattformen ausprobiert, bevor ich diese Frage gestellt habe! Die Antwort ist nicht so einfach. –

+3

Das könnte schrecklich auf Windows gehen, wo es nur die Eltern des Desktop-Verzeichnisses, die überall sein könnte ... – Chronial

15

Andere die Frage vor mir geantwortet haben, aber ein nützliches Programm, um alle verfügbaren Objekte auszudrucken ist:

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

Ich würde nicht davon abhängen, weil nicht alle Eigenschaften standardisiert sind. Überprüfen Sie stattdessen das JavaDoc für System.getProperties(), um herauszufinden, welche Eigenschaften garantiert vorhanden sind. –

+5

Das mag wahr sein, aber es ist immer noch ziemlich nützlich für einen Neuling, würde ich denken! Ich bin mir nicht sicher, dass es 2 downvotes verdient :-( –

26

Das Konzept eines HOME-Verzeichnisses scheint bei Windows etwas vage zu sein. Wenn die environment variables (HOMEDRIVE/HOMEPATH/USERPROFILE) nicht genug sind, müssen Sie möglicherweise auf native Funktionen über JNI oder JNA zurückgreifen. SHGetFolderPath können Sie spezielle Ordner abzurufen, wie My Documents (CSIDL _ PERSONAL) oder Lokale Einstellungen \ Anwendungsdaten (CSIDL _ LOCAL _ APPDATA).

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

    } 

} 
+0

FYI, der Ordner, der dem Home-Verzeichnis des Benutzers entspricht, ist CSIDL_PROFILE. Siehe http://msdn.microsoft.com/en -us/library/bb762494 (VS.85) .aspx. –

+0

Ja, das ist eine aufwendige Version für den Windows-Fall –

+0

In neueren Versionen von JNA (genauer Jna-Plattform), gibt es eine Shell32Util-Klasse, die die entsprechenden kapselt Windows-API auf eine sehr nette Art. Insbesondere sollte Shell32Util.getKnownFolderPath (...) in Kombination mit einer der Konstanten aus der KnownFolders-Klasse geeignet sein.Die ältere getFolderPath-API-Funktion ist seit Windows Vista veraltet. –

2

ich den Algorithmus in der Bug-Report mit System.getenv (String) und Rückfall der user.dir Eigenschaft verwenden, wenn keine der Umgebungsvariablen detailliert verwenden würde ein angezeigt gültiges vorhandenes Verzeichnis Dies sollte plattformübergreifend funktionieren.

Ich denke, unter Windows, was Sie wirklich sind, ist das Benutzer "Documents" Verzeichnis.

4

Als ich nach Scala-Version suchte, war alles, was ich finden konnte McDowells JNA-Code oben. Ich schließe hier meinen Scala-Port ein, da es derzeit nirgends geeigneter ist.

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

Wie bei der Java-Version, müssen Sie Java Native Access, einschließlich der beiden JAR-Dateien hinzufügen, um Ihre referenzierten Bibliotheken.

Es ist schön zu sehen, dass JNA das jetzt viel einfacher macht, als wenn der ursprüngliche Code gepostet wurde.

87

Eigentlich mit Java 8 ist der richtige Weg zu verwenden:

System.getProperty("user.home"); 

Der Fehler JDK-6519127 und die "Inkompatibilität zwischen JDK 8 und JDK 7" Abschnitt der release notes Staaten festgelegt worden ist:

Gebiet: Core-Libs/java.lang

Synopsis

Die st eps, das verwendet wurde, um das Home-Verzeichnis des Benutzers unter Windows zu ermitteln, wurde geändert, um dem von Microsoft empfohlenen Ansatz zu folgen. Diese Änderung kann in älteren Editionen von Windows beobachtet werden oder in der Registrierung Einstellungen oder Umgebungsvariablen auf andere Verzeichnisse festgelegt werden. Nature von Inkompatibilität

behavioral RFE 

6519127 

Trotz der Frage alt sein Ich lasse dies für die Zukunft.

0

Wenn Sie etwas wollen, das gut auf Windows funktioniert, gibt es ein Paket mit dem Namen WinFoldersJava, das den nativen Aufruf umschließt, um die "speziellen" Verzeichnisse unter Windows zu erhalten. Wir benutzen es häufig und es funktioniert gut.

Verwandte Themen