Java'da kullanıcıların giriş dizinini bulmanın en iyi yolu nedir?


280

Zorluk, çapraz platform olması gerektiğidir. Windows 2000, XP, Vista, OSX, Linux, diğer unix varyantları. Tüm platformlar için bunu başarabilecek bir kod snippet'i ve platformu algılamanın bir yolunu arıyorum.

Şimdi, farkında olmalı hata 4787931 o user.homeyüzden ders kitabı cevapları bana vermeyin lütfen, düzgün çalışmıyorsa, kendimi kılavuzları bu bulabilirsiniz.


1
Hatada belirtilen geçici çözümleri denediniz mi? Çok sayıda öneri var.
Joachim Sauer

1
1.4.2'ye kadar olan java sürümleri için hata 4787931, tekrar java 1.6 için hata 6519127 olarak görünür. Sorun ortadan kalkmıyor ve hala düşük öncelikli olarak listeleniyor.
GregA100k

16
Not: 4787391 hatası, Java 8
Steven R.

Yanıtlar:


366

Başvurduğunuz hata (hata 4787391) Java 8'de düzeltilmiştir. Java'nın eski bir sürümünü kullanıyor olsanız bile, System.getProperty("user.home")yaklaşım muhtemelen en iyisidir. user.homeYaklaşım vakaların çok sayıda iş gibi görünüyor. Windows'da% 100 kurşun geçirmez bir çözüm zordur, çünkü Windows ana dizinin ne anlama geldiğini değiştiren bir kavrama sahiptir.

Eğer user.homesizin için iyi yeterli değil ben bir tanımını seçme öneririm home directorypencereler için ve kullanmaya ile uygun ortam değişkeni alma System.getenv(String).


136

Aslında Java 8 ile doğru yol kullanmaktır:

System.getProperty("user.home");

JDK-6519127 hatası düzeltildi ve sürüm notlarındaki "JDK 8 ve JDK 7 arasındaki uyumsuzluklar" bölümünde şunlar belirtiliyor:

Bölge: Core Libs / java.lang

özet

Kullanıcının Windows'daki ana dizinini belirlemek için kullanılan adımlar, Microsoft tarafından önerilen yaklaşıma göre değişmiştir. Bu değişiklik, Windows'un eski sürümlerinde veya kayıt defteri ayarlarının veya ortam değişkenlerinin diğer dizinlere ayarlandığı durumlarda gözlemlenebilir. Uyumsuzluğun Doğası

behavioral RFE

6519127

Sorunun eski olmasına rağmen bunu ileride başvurmak üzere bırakıyorum.


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

Bkz. JavaDoc .


11
Hayır, doğru bir cevap değil, bu yukarıdakiyle aynı. Evet, sadece JavaDoc'ları okumadım, aynı zamanda bu soruyu sormadan önce tüm platformlarda denedim! Cevap o kadar basit değil.
Bruno Ranschaert

3
Bu, herhangi bir yerde olabilecek masaüstü dizininin
üstünü

29

HOME dizini kavramı, Windows söz konusu olduğunda biraz belirsiz görünüyor. Eğer ortam değişkenleri (homedrive / homepath / userprofıle) yeterli değildir, sen aracılığıyla yerli işlevlerini kullanarak başvurmak gerekebilir JNI veya JNA . SHGetFolderPath , Belgelerim (CSIDL_PERSONAL) veya Yerel Ayarlar \ Uygulama Verileri (CSIDL_LOCAL_APPDATA) gibi özel klasörleri almanıza olanak tanır .

Örnek JNA kodu:

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

    }

}

FYI, kullanıcının ana dizinine karşılık gelen klasör CSIDL_PROFILE'dır. Bkz. Msdn.microsoft.com/en-us/library/bb762494(VS.85).aspx .
Matt Solnit

Evet, bu Windows vakası için ayrıntılı bir sürümdür.
Bruno Ranschaert

2
JNA'nın son sürümlerinde (daha kesin olarak jna platformu), ilgili Windows API'sını çok güzel bir şekilde kapsülleyen bir Shell32Util sınıfı vardır. Özellikle, Shell32Util.getKnownFolderPath (...), KnownFolders sınıfındaki sabitlerden biriyle birlikte kullanılması uygun olmalıdır. Eski getFolderPath API işlevi Windows Vista'dan beri kullanımdan kaldırılmıştır.
Sebastian Marsching

17

Diğerleri benden önce soruyu yanıtladılar, ancak mevcut tüm özellikleri yazdırmak için yararlı bir program:

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

Tüm özellikleri standartlaştırılmadığından buna güvenmem. Bunun yerine, hangi özelliklerin varolduğunu garanti etmek için Java.oc for System.getProperties () öğesini kontrol edin.
Joachim Sauer

6
Bu doğru olabilir ama yine de sanırım bir acemi için oldukça yararlı! 2 downvotes hak ettiğinden emin değilim :-(
oxbow_lakes

6

Scala versiyonunu ararken, bulabildiğim tek şey yukarıdaki McDowell'in JNA koduydu. Scala limanımı buraya ekliyorum, çünkü şu anda daha uygun bir yer yok.

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 sürümünde olduğu gibi, başvurulan kitaplıklarınıza her iki jar dosyası da dahil olmak üzere Java Native Access'i eklemeniz gerekir .

JNA'nın bunu orijinal kodun yayınlanmasından çok daha kolay hale getirdiğini görmek güzel.


2

System.getenv (String) kullanarak hata raporunda ayrıntılı bir algoritma ve ortam değişkenlerinden hiçbiri geçerli bir dizin belirtmediyse user.dir özelliğini kullanarak geri dönüş kullanacağım. Bu, çapraz platformda çalışmalıdır.

Bence, Windows altında, kullanıcının neyin peşinde olduğunuzu, kullanıcının kavramsal "belgeler" dizinidir.


2

Alternatif olarak Apache CommonsIO FileUtils.getUserDirectory()kullanmakSystem.getProperty("user.home") . Aynı sonucu alırsınız ve sistem özelliğini belirtirken yazım hatası yapma şansınız yoktur.

Projenizde zaten Apache CommonsIO kütüphanesine sahip olma şansınız çok yüksek. Yalnızca kullanıcı ana dizinini almak için kullanmayı planlıyorsanız tanıtmayın.


0

Windows'da iyi çalışan bir şey istiyorsanız , Windows'ta 'özel' dizinleri almak için yerel çağrıyı saran WinFoldersJava adlı bir paket var . Sık kullanıyoruz ve iyi çalışıyor.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.