Javaでユーザーのホームディレクトリを見つける最良の方法は何ですか?


279

難点は、クロスプラットフォームであることです。Windows 2000、XP、Vista、OSX、Linux、その他のUNIXバリアント。すべてのプラットフォームでこれを実現できるコードのスニペットと、プラットフォームを検出する方法を探しています。

今、あなたが知っておくべきバグ4787931user.home正しく動作しませんので、教科書の答えを私に提供しないでください、私はマニュアルでこれらの自分自身を見つけることができます。


1
バグに記載されている回避策を試しましたか?たくさんの提案があります。
ヨアヒムザウアー

1
1.4.2までのJavaバージョンのバグ4787931は、Java 1.6のバグ6519127として再び表示されます。問題は解消されておらず、依然として優先度は低いと表示されています。
GregA100k

16
注:バグ4787391はJava 8で修正済みとしてマークされています
Steven R. Loomis

回答:


364

参照するバグ(バグ4787391)はJava 8で修正されました。古いバージョンのJavaを使用している場合でも、このSystem.getProperty("user.home")アプローチがおそらく最善です。このuser.homeアプローチは非常に多くのケースで機能するようです。Windowsにはホームディレクトリの意味が変わってきているため、Windowsでの100%防弾ソリューションは難しいです。が十分でない

場合user.homehome directory、Windowsの定義を選択して使用し、で適切な環境変数を取得することをお勧めしSystem.getenv(String)ます。


135

実際、Java 8では正しい方法は次のようにすることです:

System.getProperty("user.home");

バグJDK-6519127が修正され、リリースノートの「JDK 8とJDK 7の間の非互換性」セクションに次のように記載されています。

領域:コアライブラリ/ java.lang

あらすじ

Windowsでユーザーのホームディレクトリを決定するために使用される手順は、Microsoftが推奨するアプローチに従うように変更されました。この変更は、Windowsの古いエディション、またはレジストリ設定または環境変数が他のディレクトリに設定されている場合に観察可能になる可能性があります。非互換性の性質

behavioral RFE

6519127

古い質問ですが、今後の参考のために残しておきます。


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

JavaDocを参照してください。


11
いいえ、正解ではありません。これは上記と同じです。はい、JavaDocsを読んだだけでなく、この質問をする前にすべてのプラットフォームで試しました!答えはそれほど単純ではありません。
Bruno Ranschaert

3
これはWindowsではひどく間違っている可能性があり、デスクトップディレクトリの親を取得します。これはどこにでもある可能性があります…
Chronial

29

Windowsに関しては、HOMEディレクトリーの概念は少しあいまいなようです。場合は、環境変数(HOMEDRIVE / HOMEPATH / USERPROFILE)が十分ではない、あなたは経由でネイティブ関数を使用してに頼らする必要がありJNIまたはJNASHGetFolderPathを使用すると、マイドキュメント(CSIDL_PERSONAL)やLocal Settings \ Application Dataなどの特別なフォルダーを取得できます(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ケース用の精巧なバージョンです。
ブルーノランシャート2009年

2
JNAの最近のバージョン(より正確にはjna-platform)には、対応するWindows APIを非常に優れた方法でカプセル化するShell32Utilクラスがあります。特に、KnownFoldersクラスの定数の1つと組み合わせてShell32Util.getKnownFolderPath(...)を使用することが適切です。古いgetFolderPath API関数は、Windows Vista以降非推奨です。
2016年

17

他の人は私の前に質問に答えましたが、利用可能なすべてのプロパティを出力するための便利なプログラムは次のとおりです。

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

すべてのプロパティが標準化されているわけではないので、私はこれに依存しません。代わりに、JavaDocでSystem.getProperties()をチェックして、存在することが保証されているプロパティを確認してください。
ヨアヒムザウアー

6
それは本当かもしれませんが、それは私が思う初心者にとってはまだかなり役に立ちます!2票に値するかわかりません:-(
oxbow_lakes '25

6

私がScalaバージョンを探していたとき、私が見つけたのは上記のMcDowellのJNAコードだけでした。Scalaの移植版をここに含めます。現在、これ以上適切な場所はありません。

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.