2009-02-25 12 views
182

La dificultad es que debe ser multiplataforma. Windows 2000, XP, Vista, OSX, Linux, otras variantes de Unix. Estoy buscando un fragmento de código que pueda lograr esto para todas las plataformas y una forma de detectar la plataforma.¿Cuál es la mejor manera de encontrar el directorio de inicio de los usuarios en Java?

Ahora, debe tener en cuenta bug 4787931 que user.home no funciona correctamente, así que no me proporcione las respuestas de los libros de texto, puedo encontrarlas en los manuales.

+1

¿Has probado las soluciones alternativas mencionadas en el error? Hay muchas sugerencias –

+1

error 4787931 para versiones java hasta 1.4.2 aparece de nuevo como error 6519127 para java 1.6. El problema no desaparece y sigue figurando como de baja prioridad. – GregA100k

+12

Nota: el error 4787391 está marcado como arreglado en Java 8 –

Respuesta

240

El error hace referencia a (error 4787391) se ha fijado en Java 8. Incluso si está utilizando una versión anterior de Java, el enfoque System.getProperty("user.home") es probablemente el mejor. El enfoque user.home parece funcionar en una gran cantidad de casos. Una solución 100% a prueba de balas en Windows es difícil, porque Windows tiene un concepto cambiante de lo que significa el directorio de inicio.

Si user.home no es lo suficientemente bueno para usted, le sugiero que elija una definición de home directory para windows y que la use, obteniendo la variable de entorno adecuada con System.getenv(String).

+2

Finalmente, esta es la mejor solución después de todo. –

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

Véase el JavaDoc.

+8

No, no es una respuesta correcta, esta es la misma que la anterior. Sí, no solo leí los JavaDocs, sino que también los probé en todas las plataformas antes de hacer esta pregunta. La respuesta no es tan simple. –

+3

Esto podría ir terriblemente mal en Windows, donde solo tomará el padre del directorio de escritorio, que podría estar en cualquier parte ... – Chronial

15

Otros han respondido a la pregunta antes de mí, pero un programa útil para imprimir todas las propiedades disponibles es:

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

No dependería de esto, porque no todas las propiedades están estandarizadas. En su lugar, consulte JavaDoc para System.getProperties() para descubrir qué propiedades tienen la garantía de existir. –

+5

¡Eso puede ser cierto, pero aún así es bastante útil para un novato! No estoy seguro de que merezca 2 votos abajo :-( –

26

El concepto de un directorio HOME parece ser un poco vago cuando se trata de Windows. Si el environment variables (HOMEDRIVE/HOMEPATH/USERPROFILE) no es suficiente, puede que tenga que recurrir al uso de funciones nativas a través de JNI o JNA. SHGetFolderPath le permite recuperar las carpetas especiales, como Mis documentos (CSIDL _ personal) o Configuración local \ Datos de programa (CSIDL _ LOCAL _ APPDATA).

Muestra código 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); 

    } 

} 
+0

FYI, la carpeta que corresponde al directorio de inicio del usuario es CSIDL_PROFILE. Consulte http://msdn.microsoft.com/en -us/library/bb762494 (VS.85) .aspx. –

+0

Sí, esta es una versión elaborada para el caso de Windows. –

+0

En versiones recientes de JNA (más precisamente jna-platform), hay una clase Shell32Util que encapsula el correspondiente API de Windows de una manera muy agradable. En particular, usar Shell32Util.getKnownFolderPath (...) en combinación con una de las constantes de la clase KnownFolders debería ser apropiado. La función API getFolderPath anterior está en desuso desde Windows Vista. –

2

me gustaría utilizar el algoritmo se detalla en el informe de error usando System.getenv (cadena), y replegará para usar la propiedad user.dir si ninguna de las variables de entorno indicó una directorio existente válido. Esto debería funcionar multiplataforma.

Creo que, en Windows, lo que realmente buscas es el directorio de "documentos" teóricos del usuario.

4

Como estaba buscando la versión de Scala, todo lo que pude encontrar fue el código JNA de McDowell anterior. Incluyo mi puerto de Scala aquí, ya que actualmente no hay ningún lugar más apropiado.

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

Al igual que con la versión de Java, necesitará añadir Java Native Access, incluyendo tanto los archivos jar, a sus bibliotecas de referencia.

Es agradable ver que JNA ahora hace esto mucho más fácil que cuando se publicó el código original.

87

realidad con Java 8 de la manera correcta es utilizar:

System.getProperty("user.home"); 

El error JDK-6519127 ha sido fijado y las "incompatibilidades entre JDK 8 y JDK 7" de los release notes estados:

Área: Core Liberaciones/java.lang

Sinopsis

El st Los eps utilizados para determinar el directorio de inicio del usuario en Windows han cambiado para seguir el enfoque recomendado por Microsoft. Este cambio podría observarse en las ediciones anteriores de Windows o en las configuraciones de registro o variables de entorno en otros directorios. Naturaleza de Incompatibilidad

behavioral RFE 

6519127 

A pesar de la pregunta ser viejo dejo esto para futuras referencias.

0

Si quiere algo que funcione bien en Windows, hay un paquete llamado WinFoldersJava que envuelve la llamada nativa para obtener los directorios 'especiales' en Windows. Lo usamos con frecuencia y funciona bien.

Cuestiones relacionadas