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


280

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

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


1
버그에 언급 된 해결 방법을 시도 했습니까? 많은 제안이 있습니다.
— Joachim Sauer

1
1.4.2까지의 Java 버전에 대한 버그 4787931이 Java 1.6에 대한 버그 6519127로 다시 나타납니다. 문제가 해결되지 않고 여전히 낮은 우선 순위로 표시됩니다.
— GregA100k

16
참고 : 자바 (8)에 고정으로 버그 4787391가 표시됩니다
— 스티븐 R. 루미스

답변:


365

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

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


136

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

System.getProperty("user.home");

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

지역 : Core Libs / java.lang

개요

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

behavioral RFE

6519127

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


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

JavaDoc을 참조하십시오 .


11
아니요, 정답이 아닙니다. 위와 동일합니다. 예, JavaDocs를 읽었을뿐만 아니라이 질문을하기 전에 모든 플랫폼에서 사용해 보았습니다! 대답은 그렇게 간단하지 않습니다.
— Bruno Ranschaert

3
이것은 윈도우에서 끔찍하게 잘못 될 수 있는데, 어디에서든지 데스크탑 디렉토리의 부모를 취할 것입니다.
— Chronial

29

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

    }

}

참고로, 사용자의 홈 디렉토리에 해당하는 폴더는 CSIDL_PROFILE입니다. msdn.microsoft.com/en-us/library/bb762494(VS.85).aspx를 참조 하십시오 .
— Matt Solnit

예, 이것은 Windows 사례에 대한 정교한 버전입니다.
— Bruno Ranschaert

2
최신 버전의 JNA (보다 정확하게는 jna- 플랫폼)에는 해당 Windows API를 매우 멋진 방식으로 캡슐화하는 Shell32Util 클래스가 있습니다. 특히, KnownFolders 클래스의 상수 중 하나와 함께 Shell32Util.getKnownFolderPath (...)를 사용하는 것이 적절해야합니다. 이전의 getFolderPath API 함수는 Windows Vista부터 더 이상 사용되지 않습니다.
— Sebastian Marsching

17

다른 사람들은 내 질문에 대답했지만 사용 가능한 모든 속성을 인쇄하는 유용한 프로그램은 다음과 같습니다.

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

모든 속성이 표준화되지 않았기 때문에 이에 의존하지 않습니다. 대신 JavaDoc for System.getProperties ()를 확인하여 어떤 특성이 존재하는지 확인하십시오.
— Joachim Sauer

6
그것은 사실 일지 모르지만, 내가 생각할 초보자에게는 여전히 유용합니다! 나는 확실히 그것을 2 downvotes :-( 가치가 아니에요
— oxbow_lakes

6

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가 이제 원래 코드를 게시 할 때보 다 훨씬 쉽게 처리 할 수 ​​있다는 것을 알게되어 기쁩니다.


2

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

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


2

대안은 FileUtils.getUserDirectory()대신 Apache CommonsIO를 사용하는 것입니다 System.getProperty("user.home"). 동일한 결과를 얻을 수 있으며 시스템 속성을 지정할 때 오타가 발생할 가능성이 없습니다.

프로젝트에 Apache CommonsIO 라이브러리가 이미있을 가능성이 큽니다. 사용자 홈 디렉토리를 얻는 데만 사용하려는 경우 소개하지 마십시오.


0

Windows에서 잘 작동하는 것을 원한다면 WinFoldersJava 라는 패키지가있어 Windows의 '특수'디렉토리를 얻기 위해 기본 호출을 래핑합니다. 자주 사용하고 잘 작동합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.