[java] Java에서 사용자 홈 디렉토리를 찾는 가장 좋은 방법은 무엇입니까?

어려움은 크로스 플랫폼이어야한다는 것입니다. Windows 2000, XP, Vista, OSX, Linux 및 기타 유닉스 변형. 모든 플랫폼 에서이 작업을 수행 할 수있는 코드 스 니펫과 플랫폼을 감지하는 방법을 찾고 있습니다.

이제, 당신이 알고 있어야 버그 4787931user.home때문에 교과서 답변의 저를 제공하지 마십시오, 제대로 작동하지 않습니다, 나 자신은 매뉴얼에서이를 찾을 수 있습니다.



답변

참조하는 버그 (버그 4787391)는 Java 8에서 수정되었습니다. 이전 버전의 Java를 사용하더라도이 System.getProperty("user.home")방법이 여전히 가장 좋습니다. 이 user.home접근법은 매우 많은 경우에 효과가있는 것 같습니다. Windows에는 홈 디렉토리의 의미에 대한 변화하는 개념이 있기 때문에 Windows의 100 % 방탄 솔루션은 어렵습니다. 충분하지 않은

경우 Windows user.homehome directory대한 정의를 선택 하고 사용하여 적절한 환경 변수를 사용 하는 것이 좋습니다 System.getenv(String).


답변

실제로 Java 8에서 올바른 방법은 다음을 사용하는 것입니다.

System.getProperty("user.home");

버그 JDK-6519127 이 수정되었으며 릴리스 정보 의 “JDK 8과 JDK 7의 비 호환성”섹션에 다음과 같이 나와 있습니다.

지역 : Core Libs / java.lang

개요

Windows에서 사용자의 홈 디렉토리를 판별하는 데 사용되는 단계는 Microsoft 권장 접근법을 따르도록 변경되었습니다. 이 변경 사항은 이전 버전의 Windows 또는 레지스트리 설정 또는 환경 변수가 다른 디렉토리로 설정된 경우에 관찰 될 수 있습니다. 비 호환성의 본질

behavioral RFE

6519127

오래된 질문에도 불구하고 나중에 참조 할 수 있도록 남겨 두십시오.


답변

System.getProperty("user.home");

JavaDoc을 참조하십시오 .


답변

HOME 디렉토리의 개념은 Windows와 관련하여 약간 모호한 것 같습니다. 경우 환경 변수 (HOMEDRIVE / HOMEPATH / USERPROFILE)가 충분하지 않습니다, 당신은을 통해 기본 기능을 사용하여에 의존 할 수 있습니다 JNI 또는 JNA . 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 버전을 검색 할 때 위의 McDowell의 JNA 코드 만 찾을 수있었습니다. 현재 더 적절한 곳이 없기 때문에 여기에 스칼라 포트를 포함시킵니다.

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 버전과 마찬가지로 두 jar 파일을 포함하여 Java Native Access 를 참조 라이브러리 에 추가해야합니다 .

JNA가 이제 원래 코드를 게시 할 때보 다 훨씬 쉽게 처리 할 수 ​​있다는 것을 알게되어 기쁩니다.


답변

System.getenv (String)를 사용하여 버그 보고서에 자세히 설명 된 알고리즘을 사용하고 유효한 기존 디렉토리를 나타내는 환경 변수가 없으면 user.dir 속성을 사용하여 대체합니다. 이것은 크로스 플랫폼에서 작동합니다.

Windows에서 여러분이 실제로 따르는 것은 사용자의 명목상의 “문서”디렉토리라고 생각합니다.