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


280

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

이제, 당신이 알고 있어야 버그 4787931user.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.homehome 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.