難点は、クロスプラットフォームである必要があることです。 Windows 2000、XP、Vista、OSX、Linux、その他のUNIXバリアント。すべてのプラットフォームでこれを実現できるコードのスニペットと、プラットフォームを検出する方法を探しています。
bug 4787931user.home
が正しく動作しないことに注意してください。教科書の答えを提供しないでください。これらはマニュアルで確認できます。
参照するバグ(バグ4787391)はJava 8で修正されています。古いバージョンのJavaを使用している場合でも、おそらくSystem.getProperty("user.home")
アプローチが最適です。 user.home
アプローチは、非常に多くの場合に機能するようです。 Windowsにはホームディレクトリが何を意味するかという概念が変化しているため、Windowsでの完全な防弾ソリューションは困難です。user.home
で十分でない場合は、Windows用にhome directory
の定義を選択して使用し、System.getenv(String)
で適切な環境変数を取得することをお勧めします。
実際、Java 8を使用する正しい方法は次のとおりです。
System.getProperty("user.home");
バグ JDK-6519127 は修正され、 リリースノート の「JDK 8とJDK 7の非互換性」セクションには次のように記載されています。
分野:コアライブラリ/ Java.lang
あらすじ
Windowsでユーザーのホームディレクトリを決定するために使用される手順は、マイクロソフトが推奨するアプローチに従うように変更されました。この変更は、Windowsの古いエディション、またはレジストリ設定または環境変数が他のディレクトリに設定されている場合に確認できます。非互換性の性質
behavioral RFE 6519127
質問は古くなっていますが、今後の参考のために残しておきます。
System.getProperty("user.home");
JavaDoc を参照してください。
HOMEディレクトリの概念は、Windowsに関しては少し曖昧に思えます。 環境変数 (HOMEDRIVE/HOMEPATH/USERPROFILE)だけでは不十分な場合、 JNI または JNAを使用してネイティブ関数を使用する必要がある場合があります。 。 SHGetFolderPath は、My Documents(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);
}
}
他の人が私の質問に答えましたが、利用可能なすべてのプロパティを印刷する便利なプログラムは次のとおりです。
for (Map.Entry<?,?> e : System.getProperties().entrySet()) {
System.out.println(String.format("%s = %s", e.getKey(), e.getValue()));
}
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により、元のコードが投稿されたときよりもはるかに簡単になったことがわかります。
System.getenv(String)を使用してバグレポートに詳述されているアルゴリズムを使用し、環境変数のいずれも有効な既存のディレクトリを示していない場合はuser.dirプロパティを使用するフォールバックを使用します。これはクロスプラットフォームで動作するはずです。
私は、Windowsでは、あなたが本当に望んでいるのはユーザーの概念的な「ドキュメント」ディレクトリだと思います。
Windowsで適切に動作するものが必要な場合は、 WinFoldersJava というパッケージがあります。これは、Windowsで「特別な」ディレクトリを取得するためのネイティブ呼び出しをラップします。頻繁に使用し、うまく機能します。
代わりに、FileUtils.getUserDirectory()
の代わりにApache CommonsIO System.getProperty("user.home")
を使用することもできます。同じ結果が得られ、システムプロパティを指定するときにタイプミスを引き起こす可能性はありません。
プロジェクトにApache CommonsIOライブラリが既にある可能性があります。ユーザーのホームディレクトリを取得するためだけに使用する場合は、導入しないでください。