Çalışan bir JAR dosyasının yolunu nasıl alabilirim?


580

Kodum foo.jar diyelim bir JAR dosyası içinde çalışır ve kodda, hangi foo.jar çalışan klasöründe bilmeliyim .

Yani, foo.jar içeriyorsa , C:\FOO\şu anki çalışma dizinim ne olursa olsun bu yolu almak istiyorum.


Yollar boşluk içerdiğinde çalışan bir çözüm için Fab'ın cevabına bakın. Ayrıca, aşağıdaki bazı yanıtların başlıktaki soruyu (jar yolu), bazılarının da sorunun kendisini (jar içeren klasör yolu) ve bazılarının da jar dosyası içindeki sınıflara yol sağladığını unutmayın.
Andy Thomas

32
ANT içinde kullanırken dikkatli olun! ============== Dize çağırıyorum path = SomeClass.class.getProtectionDomain (). GetCodeSource (). GetLocation (). GetPath (); ve alın: /C:/apache-ant-1.7.1/lib/ant.jar Çok yararlı değil!
Dino Fancellu

İlginç. Bunu kullandığım orijinal kod asla karıncada çalıştırılmadı, bu yüzden benim için bir sorun değil.
Thiago Chaves

2
@Dino Fancellu, tam olarak tarif ettiğiniz şeyi yaşadım. Geliştirme sırasında çalışır, kavanoza inşa edildiğinde başarısız olur.
Buddy

Yanıtlar:


539
return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation()
    .toURI()).getPath();

"Sınıfım" yerine sınıfınızın adını yazın.

Açıkçası, sınıfınız dosya olmayan bir konumdan yüklendiyse bu garip şeyler yapacaktır.


43
toURI()Adım boşluklar ve artılar dahil özel karakterler içeren önlemek sorunlarına hayati önem taşımaktadır. Doğru tek astar: return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().toURI()); Kullanmak URLDecoderbirçok özel karakter için çalışmaz. Daha fazla ayrıntı için aşağıdaki cevabıma bakın.
ctrueden

4
Not: Bu, jar dosyasının adını içeren yolu döndürür
Buddy

8
Bu, çalışan dizin yerine jar dosyasına işaret etmiyor mu? Bu çalışma için sonuç getParentFile () üzerinde bir yapmanız gerekir.
FOO

1
Ayrıca, getProtectionDomainbir stracktrace dan sınıf alıyorsanız null:val strace = Thread.currentThread().getStackTrace; val path = strace(1).getClass.getProtectionDomain
bbarker

1
Java 8'e kadar olan bu yöntemi kullanarak; bu yöntemi, sınıf yolu aracılığıyla yüklenen harici bir Kavanozun içindeki bir sınıfa yerleştirdikten sonra, gerçek çalışan Kavanoz yerine dış kavanozun yolu verilecektir.
Mr00Anderson

189

Benim için en iyi çözüm:

String path = Test.class.getProtectionDomain().getCodeSource().getLocation().getPath();
String decodedPath = URLDecoder.decode(path, "UTF-8");

Bu, boşluk ve özel karakterlerle sorunu çözmelidir.


8
Bir not daha: Bu işlevi Jar'dan çağırırken, kavanozun adı benim için sonuna eklenir, bu nedenle yürütmek zorunda kaldı: path.substring (0, path.lastIndexOf ("/") + 1);
will824

11
/ mutlaka yol ayırıcı değildir. Bunun yerine (yeni Dosya (yol)) .getParentFile (). GetPath () yapmalısınız.
pjz

10
JAR dosya adının buraya eklenmesiyle ilgili bir sorun yok. UTF dönüşümü URLDecoder.decode(ClassLoader.getSystemClassLoader().getResource(".").getPath(), "UTF-8");, Linux'ta @Iviggiani's (( ) ile birlikte mükemmel bir çözüm gibi görünüyor . Ancak, Windows üzerinde denemedim.
Ubuntudroid

2
Teşekkür ederim, bu hem Linux hem de Windows'da FileInputStream ile JAR'ım dışındaki dosyaları yüklememe izin verdi. Sadece dosya adının önünde çözülmüş yolu eklemek zorunda ...
giorgio79

11
Dikkat: URLDecoderözel karakterlerin kodunu çözmek için kullanılması önerilmez . Özellikle, gibi karakterlerin +boşluklara yanlışlıkla kodu çözülecektir. Ayrıntılar için cevabıma bakın.
ctrueden

153

Belirli bir için elde etmek Fileiçin Classiki adım vardır:

  1. Dönüştürme Classa kadarURL
  2. Dönüştürme URLa kadarFile

Her iki adımı da anlamak ve onları karıştırmamak önemlidir.

Bir kez sahip olduktan sonra File, getParentFileihtiyacınız olan şey varsa, içeren klasörü almak için arayabilirsiniz .

Adım 1: Class-URL

Diğer cevaplarda tartışıldığı gibi, a ile URLilgili bulmanın iki ana yolu vardır Class.

  1. URL url = Bar.class.getProtectionDomain().getCodeSource().getLocation();

  2. URL url = Bar.class.getResource(Bar.class.getSimpleName() + ".class");

Her ikisinin de artıları ve eksileri var.

getProtectionDomainYaklaşım sınıfı (örneğin, içeren JAR dosyası) taban bölgesi elde edilir. Bununla birlikte, Java çalışma zamanının güvenlik ilkesinin SecurityExceptionarama sırasında ortaya çıkması mümkündür getProtectionDomain(), bu nedenle uygulamanızın çeşitli ortamlarda çalışması gerekiyorsa, hepsini test etmek en iyisidir.

getResourceYaklaşım ek dize kullanımı uygulamanız gerekir hangi sınıfa ait tam URL kaynak yolunu verir. Bir file:yol olabilir , ancak bir OSGi çerçevesi içinde yürütülürken olduğu jar:file:gibi hatta daha nahoş bir şey de olabilir bundleresource://346.fwk2106232034:4/foo/Bar.class. Tersine, getProtectionDomainyaklaşım file:OSGi içinden bile doğru bir URL verir .

Hem o Not getResource("")ve getResource(".")sınıf bir JAR dosyası içinde ikamet, benim testlerde başarısız; her iki çağrı da boş döndü. Bu yüzden yukarıda gösterilen # 2 çağrısını daha güvenli göründüğünden tavsiye ederim.

2.Adım: URL-File

Her iki durumda da, a'ya sahip olduğunuzda, bir URLsonraki adım a'ya dönüştürülür File. Bu kendi zorluğudur; bkz konuda Kohsuke Kawaguchi adlı blog yazısı tüm detaylar için, ama kısacası kullanabilirsiniz new File(url.toURI())sürece URL tamamen iyi biçimli olarak.

Son olarak, kullanmayı şiddetle tavsiye ederim URLDecoder. URL Bazı karakterler :ve /özellikle de geçerli URL olarak kodlanmış karakterleri kullanılamaz. Gönderen URLDecoder Javadoc:

Kodlanan dizedeki tüm karakterlerin aşağıdakilerden biri olduğu varsayılır: "a" - "z", "A" - "Z", "0" - "9" ve "-", "_", " .", ve "*". "%" Karakterine izin verilir, ancak özel bir çıkış dizisinin başlangıcı olarak yorumlanır.

...

Bu kod çözücünün yasadışı dizelerle başa çıkmasının iki olası yolu vardır. Yasadışı karakterleri yalnız bırakabilir veya bir IllegalArgumentException kurabilir. Kod çözücünün hangi yaklaşımı uyguladığı uygulamaya bırakılır.

Uygulamada, URLDecodergenellikle IllegalArgumentExceptionyukarıda tehdit edildiği gibi atmaz . Dosya yolunuz olarak kodlanmış boşluklar varsa %20, bu yaklaşım işe yarayabilir. Ancak, dosya yolunuzda başka alfa olmayan karakterler varsa, dosya yolunuzu yönetmeyle +ilgili sorunlarınız olacaktır URLDecoder.

Çalışma kodu

Bu adımları gerçekleştirmek için aşağıdakine benzer yöntemleriniz olabilir:

/**
 * Gets the base location of the given class.
 * <p>
 * If the class is directly on the file system (e.g.,
 * "/path/to/my/package/MyClass.class") then it will return the base directory
 * (e.g., "file:/path/to").
 * </p>
 * <p>
 * If the class is within a JAR file (e.g.,
 * "/path/to/my-jar.jar!/my/package/MyClass.class") then it will return the
 * path to the JAR (e.g., "file:/path/to/my-jar.jar").
 * </p>
 *
 * @param c The class whose location is desired.
 * @see FileUtils#urlToFile(URL) to convert the result to a {@link File}.
 */
public static URL getLocation(final Class<?> c) {
    if (c == null) return null; // could not load the class

    // try the easy way first
    try {
        final URL codeSourceLocation =
            c.getProtectionDomain().getCodeSource().getLocation();
        if (codeSourceLocation != null) return codeSourceLocation;
    }
    catch (final SecurityException e) {
        // NB: Cannot access protection domain.
    }
    catch (final NullPointerException e) {
        // NB: Protection domain or code source is null.
    }

    // NB: The easy way failed, so we try the hard way. We ask for the class
    // itself as a resource, then strip the class's path from the URL string,
    // leaving the base path.

    // get the class's raw resource path
    final URL classResource = c.getResource(c.getSimpleName() + ".class");
    if (classResource == null) return null; // cannot find class resource

    final String url = classResource.toString();
    final String suffix = c.getCanonicalName().replace('.', '/') + ".class";
    if (!url.endsWith(suffix)) return null; // weird URL

    // strip the class's path from the URL string
    final String base = url.substring(0, url.length() - suffix.length());

    String path = base;

    // remove the "jar:" prefix and "!/" suffix, if present
    if (path.startsWith("jar:")) path = path.substring(4, path.length() - 2);

    try {
        return new URL(path);
    }
    catch (final MalformedURLException e) {
        e.printStackTrace();
        return null;
    }
} 

/**
 * Converts the given {@link URL} to its corresponding {@link File}.
 * <p>
 * This method is similar to calling {@code new File(url.toURI())} except that
 * it also handles "jar:file:" URLs, returning the path to the JAR file.
 * </p>
 * 
 * @param url The URL to convert.
 * @return A file path suitable for use with e.g. {@link FileInputStream}
 * @throws IllegalArgumentException if the URL does not correspond to a file.
 */
public static File urlToFile(final URL url) {
    return url == null ? null : urlToFile(url.toString());
}

/**
 * Converts the given URL string to its corresponding {@link File}.
 * 
 * @param url The URL to convert.
 * @return A file path suitable for use with e.g. {@link FileInputStream}
 * @throws IllegalArgumentException if the URL does not correspond to a file.
 */
public static File urlToFile(final String url) {
    String path = url;
    if (path.startsWith("jar:")) {
        // remove "jar:" prefix and "!/" suffix
        final int index = path.indexOf("!/");
        path = path.substring(4, index);
    }
    try {
        if (PlatformUtils.isWindows() && path.matches("file:[A-Za-z]:.*")) {
            path = "file:/" + path.substring(5);
        }
        return new File(new URL(path).toURI());
    }
    catch (final MalformedURLException e) {
        // NB: URL is not completely well-formed.
    }
    catch (final URISyntaxException e) {
        // NB: URL is not completely well-formed.
    }
    if (path.startsWith("file:")) {
        // pass through the URL as-is, minus "file:" prefix
        path = path.substring(5);
        return new File(path);
    }
    throw new IllegalArgumentException("Invalid URL: " + url);
}

Aşağıdaki yöntemleri SciJava Common kütüphanesinde bulabilirsiniz:


5
+ 1; bugüne kadarki en iyi cevap: işletim sistemi için doğru gösterimi kullanarak yolu döndürecektir. (örneğin, pencereler için \).
Bathsheba

Güvenlikle ilgili olarak, Java WebStart'ın buna izin vermediğini bulduğuma inanıyorum.
Thorbjørn Ravn Andersen

55

Ayrıca kullanabilirsiniz:

CodeSource codeSource = YourMainClass.class.getProtectionDomain().getCodeSource();
File jarFile = new File(codeSource.getLocation().toURI().getPath());
String jarDir = jarFile.getParentFile().getPath();

3
Bu benim için daha iyi çalışıyor, çünkü kavanozun yolunu veriyor, sınıftan değil!
T30

Benim için de çalıştı. Fab'ın cevabı ile birleştirin ve daha iyi olsun!
Danielson Alves Júnior

25

Geçerli sınıfınızın URL'sini bulmak için ClassLoader.getResource () öğesini kullanın.

Örneğin:

package foo;

public class Test
{
    public static void main(String[] args)
    {
        ClassLoader loader = Test.class.getClassLoader();
        System.out.println(loader.getResource("foo/Test.class"));
    }
}

(Bu örnek benzer bir sorudan alınmıştır .)

Dizini bulmak için URL'yi manuel olarak ayırmanız gerekir. Bir kavanoz URL'sinin biçimi için JarClassLoader öğreticisine bakın .


JAR dosyam gizlendi, bu yüzden bu cevap sorunumu çözmedi. Ama bunu soruda belirtmedim, bu hala geçerli bir cevap.
Thiago Chaves

12
Gizlenmişse, Test.class.getName () kullanın ve uygun munging yapın.
Jon Skeet

1
@JonSkeet Cevabınızla ilgili çok fazla sorun var: 1. Hayır, NPEçünkü sorulan soruya cevap vermediniz (JAR dir yolu yolu soruldu ve kesinlikle farklı bir soruya cevap verdiniz: sınıf yolu). 2. Başkaları tarafından işaret edildiği gibi, ben de aynı sorunu var, appletler için işe yaramaz. 3. İade yolu hiç kanonik yol temsilinin değil: jar:file:/listener/build/libs/listener-1.0.0-all.jar!/shared/Test.class.
WhiteAngel

1
@WhiteAngel: 1) Yazımın son satırı, URL'ye bakmanız ve jar dosyasını almak için bunu ayırmanız gerektiğini gösterir. Kabul ediyorum en eksiksiz cevap değil, ama tartışmaya değer gerçekten çok kötü olduğunu düşünmüyorum (özellikle 10 yıl sonra ...) 2) Burada herhangi bir yorumda Applets bahsedilmedi - garip yeterince, ben don Bir cevap gönderdiğim sorularla ilgili tüm cevaplar hakkındaki tüm yorumlara bakmak için zamanım yok. 3) Yine, jar URL'sinin biçimine bağlarım.
Jon Skeet

2
@WhiteAngel: Bu şimdiye kadar yazdığım en iyi cevap mı? Hayır! Olmasını sağladığınız kadar kötü mü? Hayır, sanmıyorum. (Özellikle etrafında yaptığınız iddialar açısından, bir NPE atma, ki öyle değil.) Bu konuda bir yaygara yapmak yerine kendi cevabınızı eklemenizi öneririm. Bu daha olumlu bir yaklaşım olurdu.
Jon Skeet

19

Son zamanlarda hiçbirinin kullanılmasını önermediğini görünce şaşırdım Path. ": Burada atıf aşağıdaki bir yolunun diğer formları, ya da özü kısımlarına yolu dönüştürmek sınıfı çeşitli yolu hakkında bilgi elde etmek için kullanılabilecek yöntem, yolun erişim elemanları içerir "Path

Bu nedenle, iyi bir alternatif, Pathnesneyi şu şekilde elde etmektir :

Path path = Paths.get(Test.class.getProtectionDomain().getCodeSource().getLocation().toURI());

3
Not olarak, Yol Java 7'den başlayarak kullanılabilir.
Chris Forrence

15

Linux, Mac ve Windows'ta benim için çalışan tek çözüm:

public static String getJarContainingFolder(Class aclass) throws Exception {
  CodeSource codeSource = aclass.getProtectionDomain().getCodeSource();

  File jarFile;

  if (codeSource.getLocation() != null) {
    jarFile = new File(codeSource.getLocation().toURI());
  }
  else {
    String path = aclass.getResource(aclass.getSimpleName() + ".class").getPath();
    String jarFilePath = path.substring(path.indexOf(":") + 1, path.indexOf("!"));
    jarFilePath = URLDecoder.decode(jarFilePath, "UTF-8");
    jarFile = new File(jarFilePath);
  }
  return jarFile.getParentFile().getAbsolutePath();
}

Bu işe yaramayacak. Linux'ta ise, toUri () yöntemi bir istisna atar ve linux için başka bir kısma ulaşmazsınız.
Wilhelm Sorban

9

Aynı sorunu yaşadım ve bu şekilde çözdüm:

File currentJavaJarFile = new File(Main.class.getProtectionDomain().getCodeSource().getLocation().getPath());   
String currentJavaJarFilePath = currentJavaJarFile.getAbsolutePath();
String currentRootDirectoryPath = currentJavaJarFilePath.replace(currentJavaJarFile.getName(), "");

Umarım size yardımcı olmuştum.


Bunu yapma. URL.getPath () etmez bir dosya adı döndürülür ve bu onları boşluk olan dosya yolları gibi durumlarda, bir çok başarısız olur.
VGR

9

İşte bana bazı ayrıntılar için yükseltme gibi görünüyor,

.jar dosyasının dışında göreli bir "klasör" kullanma (kavanozun aynı konumunda):

String path = 
  YourMainClassName.class.getProtectionDomain().
  getCodeSource().getLocation().getPath();

path = 
  URLDecoder.decode(
    path, 
    "UTF-8");

BufferedImage img = 
  ImageIO.read(
    new File((
        new File(path).getParentFile().getPath()) +  
        File.separator + 
        "folder" + 
        File.separator + 
        "yourfile.jpg"));

4
Dikkat: URLDecoderözel karakterlerin kodunu çözmek için kullanılması önerilmez . Özellikle, gibi karakterlerin +boşluklara yanlışlıkla kodu çözülecektir. Ayrıntılar için cevabıma bakın.
ctrueden

Dosya adlarında özel karakterler kullanılması önerilmez.
Zon

URLDecoder, ismine rağmen, URL kodunu çözmek ve URL'leri değil, parametre adlarını ve değerlerini oluşturmak içindir.
Lorne Marquis

6

Jar dosyasını çalıştırma yolunu elde etmek için yukarıdaki çözümleri inceledim ve birbirinden biraz farklı olan tüm yöntemleri denedim. Bu kod Eclipse IDE'de çalışıyorsa, belirtilen sınıf da dahil olmak üzere dosyanın yolunu bulabilmeli ve bulunan yolla belirtilen bir dosyayı açmalı veya oluşturabilmelidir.

Ancak zor, runnable jar dosyasını doğrudan veya komut satırı üzerinden çalıştırdığınızda, yukarıdaki yöntemlerden alınan jar dosyasının yolu jar dosyasında dahili bir yol vereceği için başarısız olacaktır, yani her zaman bir yol verir gibi

rsrc: project-name (belki de ana sınıf dosyasının paket adı olduğunu söylemeliyim - belirtilen sınıf)

Harici bir yola rsrc: ... yolunu dönüştüremiyorum, yani Eclipse IDE dışında jar dosyasını çalıştırdığınızda jar dosyasının yolunu alamıyorum.

Eclipse IDE dışında jar dosyasını çalıştırma yolunu almanın tek yolu

System.getProperty("java.class.path")

bu kod satırı, java belgesi olarak ve bazı insanlar tüm sınıf dosyalarının yollarını döndüreceğini söylediğinde, çalışan jar dosyasının yaşam yolunu (dosya adı dahil) (dönüş yolunun çalışma dizini olmadığını unutmayın) döndürebilir. aynı dizinde, ancak aynı dizinde birçok jar dosyası içeriyorsa testlerim olarak, sadece jar çalıştıran yolu döndürür (aslında Eclipse'de gerçekleşen birden fazla yol sorunu hakkında).


java.class.pathçok değerli olabilir. Bu değerlerden biri kesinlikle geçerli sınıfın bulunduğu dizini veya JAR dosyasını sağlayacaktır, ancak hangisi?
Lorne Marquis

Doğruladım, başka çözümler denedim, ama asla kavanoz dosya adını alamadım. Bu çok basit çalışıyor! teşekkürler - +1
guillaume girod-vitouchkina

5

Diğer yanıtlar, dizin olmayan Jar dosyası konumu olan kod kaynağına işaret ediyor gibi görünüyor.

kullanım

return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()).getParentFile();

Sınıflarınızı JAR dosyası yerine bir dosya sisteminden yüklüyorsanız, örneğin hata ayıklama sırasında bir dizin olabilir.
Lorne Marquis

4

kavanozunuzu Gnome masaüstü ortamından (herhangi bir komut dosyasından veya terminalden değil) tıklatarak çalıştırırsanız yukarıdaki seçilen cevap çalışmaz.

Bunun yerine, aşağıdaki çözümün her yerde çalıştığını sevdim:

    try {
        return URLDecoder.decode(ClassLoader.getSystemClassLoader().getResource(".").getPath(), "UTF-8");
    } catch (UnsupportedEncodingException e) {
        return "";
    }

2
Bunu bir uygulamada veya bir uygulamada denediniz mi? Java Web Start kullanılarak başlatıldı? Benim anlayışım, her iki durumda da başarısız olacağıdır (uygulama güvenilir olsa bile).
Andrew Thompson

Bu çözüm yalnızca "." içinde JAR dosyası değil konum ait JAR dosyası.
Lorne Marquis

Dikkat: URLDecoderözel karakterlerin kodunu çözmek için kullanılması önerilmez . Özellikle, gibi karakterlerin +boşluklara yanlışlıkla kodu çözülecektir. Ayrıntılar için cevabıma bakın.
ctrueden

Bahar önyükleme, atacakNullPointerException
Ravi Parekh

NPEJAR'da kaynak yoksa sahip olacaksınız .
WhiteAngel

3

Aslında burada daha iyi bir sürüm var - eski bir klasör adında boşluk varsa başarısız oldu.

  private String getJarFolder() {
    // get name and path
    String name = getClass().getName().replace('.', '/');
    name = getClass().getResource("/" + name + ".class").toString();
    // remove junk
    name = name.substring(0, name.indexOf(".jar"));
    name = name.substring(name.lastIndexOf(':')-1, name.lastIndexOf('/')+1).replace('%', ' ');
    // remove escape characters
    String s = "";
    for (int k=0; k<name.length(); k++) {
      s += name.charAt(k);
      if (name.charAt(k) == ' ') k += 2;
    }
    // replace '/' with system separator char
    return s.replace('/', File.separatorChar);
  }

Küçük uygulamalarda başarısızlığa gelince, genellikle yerel dosyalara erişemezsiniz. JWS hakkında çok şey bilmiyorum ama yerel dosyaları işlemek için uygulamayı indirmek mümkün olmayabilir.


Yolu çözmek için birkaç yerleşik yol vardır. Kendi kodunuzu yazmanıza gerek yok.
Lorne Marquis

3

Kavanozu kullanarak koşu yolunu almaya çalıştım

String folder = MyClassName.class.getProtectionDomain().getCodeSource().getLocation().getPath();

c: \ app> java -jar application.jar

"Application.jar" adlı jar uygulamasını çalıştırarak, Windows'ta " c: \ app " klasöründeki "String" klasörü değişkeninin değeri " \ c: \ app \ application.jar " idi ve sınamada sorunlar yaşadım yolun doğruluğu

File test = new File(folder);
if(file.isDirectory() && file.canRead()) { //always false }

Bu yüzden "test" i şöyle tanımlamaya çalıştım:

String fold= new File(folder).getParentFile().getPath()
File test = new File(fold);

yolu " \ c: \ app \ application.jar " yerine " c: \ app " gibi doğru bir biçimde almak ve ben bunun işe yaradığını fark ettim.


3

En basit çözüm, kavanozu çalıştırırken yolu bir argüman olarak geçirmektir.

Bunu bir kabuk komut dosyasıyla otomatikleştirebilirsiniz (Windows'ta .bat, başka bir yerde .sh):

java -jar my-jar.jar .

.Geçerli çalışma dizinini geçirdim .

GÜNCELLEME

Jar dosyasını bir alt dizine yapıştırmak isteyebilirsiniz, böylece kullanıcılar yanlışlıkla tıklamaz. Kodunuz ayrıca komut satırı bağımsız değişkenlerinin sağlandığından emin olmalı ve bağımsız değişkenler eksikse iyi bir hata iletisi vermelidir.


3

Sonunda çalışan (ve kısa) bir çözüm bulamadan önce çok uğraşmak zorunda kaldım. Kullanarak çıkarılabilen veya gibi bir önekle
gelmesi mümkündür .jarLocationfile:\jar:file\String#substring()

URL jarLocationUrl = MyClass.class.getProtectionDomain().getCodeSource().getLocation();
String jarLocation = new File(jarLocationUrl.toString()).getParent();

2
String path = getClass().getResource("").getPath();

Yol her zaman jar dosyası içindeki kaynağa başvurur.


1
Bu yol dizgisinin hâlâ ihtiyaçlarınıza göre sadeleştirilmesi gerekiyor. String path = new File(getClass().getResource("").getPath()).getParentFile().getParent(); File jarDir = new File(path.substring(5));
ZZZ

4
Hem getResource("")ve getResource(".")benim testlerde başarısız, sınıf bir JAR dosyası içinde ikamet zaman; her iki çağrı da boş döndü.
ctrueden

2
Bu atar NullPointerException.
Lorne Marquis

2
public static String dir() throws URISyntaxException
{
    URI path=Main.class.getProtectionDomain().getCodeSource().getLocation().toURI();
    String name= Main.class.getPackage().getName()+".jar";
    String path2 = path.getRawPath();
    path2=path2.substring(1);

    if (path2.contains(".jar"))
    {
        path2=path2.replace(name, "");
    }
    return path2;}

Windows'da iyi çalışır


1

Sinir bozucu bir şey, Eclipse geliştirdiğinizde harika MyClass.class.getProtectionDomain().getCodeSource().getLocation()olan /bindizini döndürür , ancak bir kavanoza derlediğinizde, yolun /myjarname.jarsize yasadışı dosya adları veren bölümü içermesidir.

Kodun hem ide'de çalışması için hem de bir kavanoza derlendiğinde, aşağıdaki kod parçasını kullanıyorum:

URL applicationRootPathURL = getClass().getProtectionDomain().getCodeSource().getLocation();
File applicationRootPath = new File(applicationRootPathURL.getPath());
File myFile;
if(applicationRootPath.isDirectory()){
    myFile = new File(applicationRootPath, "filename");
}
else{
    myFile = new File(applicationRootPath.getParentFile(), "filename");
}

1

Gerçekten diğerleri hakkında emin değilim ama benim durumumda bir "Runnable kavanoz" ile işe yaramadı ve ben phchen2 cevap ve bu bağlantıdan başka bir kod birlikte sabitleyerek çalışma var: Nasıl çalışan bir JAR dosyasının yolunu almak için? Kod:

               String path=new java.io.File(Server.class.getProtectionDomain()
                .getCodeSource()
                .getLocation()
                .getPath())
          .getAbsolutePath();
       path=path.substring(0, path.lastIndexOf("."));
       path=path+System.getProperty("java.class.path");

1

Orada birkaç çözüm denedim ama hiçbiri çalıştırılabilir kavanoz Eclipse "Ambalaj dış kütüphaneler" ile ihraç (muhtemelen özel) durumda doğru sonuçlar vermedi. Bazı nedenlerden dolayı, ProtectionDomain tabanlı tüm çözümler bu durumda null sonucunu verir.

Yukarıdaki bazı çözümleri birleştirerek aşağıdaki çalışma kodunu elde etmeyi başardım:

String surroundingJar = null;

// gets the path to the jar file if it exists; or the "bin" directory if calling from Eclipse
String jarDir = new File(ClassLoader.getSystemClassLoader().getResource(".").getPath()).getAbsolutePath();

// gets the "bin" directory if calling from eclipse or the name of the .jar file alone (without its path)
String jarFileFromSys = System.getProperty("java.class.path").split(";")[0];

// If both are equal that means it is running from an IDE like Eclipse
if (jarFileFromSys.equals(jarDir))
{
    System.out.println("RUNNING FROM IDE!");
    // The path to the jar is the "bin" directory in that case because there is no actual .jar file.
    surroundingJar = jarDir;
}
else
{
    // Combining the path and the name of the .jar file to achieve the final result
    surroundingJar = jarDir + jarFileFromSys.substring(1);
}

System.out.println("JAR File: " + surroundingJar);

1

Bunu dene:

String path = new File("").getAbsolutePath();

0

Arşivdeki koddan çağrılan bu yöntem, .jar dosyasının bulunduğu klasörü döndürür. Windows veya Unix'te çalışmalıdır.


  private String getJarFolder() {
    String name = this.getClass().getName().replace('.', '/');
    String s = this.getClass().getResource("/" + name + ".class").toString();
    s = s.replace('/', File.separatorChar);
    s = s.substring(0, s.indexOf(".jar")+4);
    s = s.substring(s.lastIndexOf(':')-1);
    return s.substring(0, s.lastIndexOf(File.separatorChar)+1);
  } 

Şu koddan türetildi: JAR'dan çalıştırılıp çalıştırılmadığını belirleyin


3
"Windows veya Unix'te çalışmalıdır." ancak herhangi bir uygulamada ve her uygulamada başarısız olur. JWS kullanılarak başlatıldı.
Andrew Thompson

0

Sadece kontrol edilir Windowsama diğer İşletim Sistemleri [ Linux,MacOs,Solaris] :) mükemmel çalıştığını düşünüyorum .


Aynı dizinde 2 .jar dosyam vardı . Bir .jardosyadan .jaraynı dizindeki diğer dosyayı başlatmak istedim .

Sorun, cmdgeçerli dizinden başlattığınızda olmasıdır system32.


Uyarılar!

  • Aşağıdaki klasör adı ile bile yaptığım tüm test oldukça iyi çalışıyor gibi görünüyor ;][[;'57f2g34g87-8+9-09!2#@!$%^^&()veya ()%&$%^@# iyi çalışıyor.
  • ProcessBuilderAşağıdaki gibi aşağıdaki ile kullanıyorum :

🍂 ..

//The class from which i called this was the class `Main`
String path = getBasePathForClass(Main.class);
String applicationPath=  new File(path + "application.jar").getAbsolutePath();


System.out.println("Directory Path is : "+applicationPath);

//Your know try catch here
//Mention that sometimes it doesn't work for example with folder `;][[;'57f2g34g87-8+9-09!2#@!$%^^&()` 
ProcessBuilder builder = new ProcessBuilder("java", "-jar", applicationPath);
builder.redirectErrorStream(true);
Process process = builder.start();

//...code

🍂 getBasePathForClass(Class<?> classs):

    /**
     * Returns the absolute path of the current directory in which the given
     * class
     * file is.
     * 
     * @param classs
     * @return The absolute path of the current directory in which the class
     *         file is.
     * @author GOXR3PLUS[StackOverFlow user] + bachden [StackOverFlow user]
     */
    public static final String getBasePathForClass(Class<?> classs) {

        // Local variables
        File file;
        String basePath = "";
        boolean failed = false;

        // Let's give a first try
        try {
            file = new File(classs.getProtectionDomain().getCodeSource().getLocation().toURI().getPath());

            if (file.isFile() || file.getPath().endsWith(".jar") || file.getPath().endsWith(".zip")) {
                basePath = file.getParent();
            } else {
                basePath = file.getPath();
            }
        } catch (URISyntaxException ex) {
            failed = true;
            Logger.getLogger(classs.getName()).log(Level.WARNING,
                    "Cannot firgue out base path for class with way (1): ", ex);
        }

        // The above failed?
        if (failed) {
            try {
                file = new File(classs.getClassLoader().getResource("").toURI().getPath());
                basePath = file.getAbsolutePath();

                // the below is for testing purposes...
                // starts with File.separator?
                // String l = local.replaceFirst("[" + File.separator +
                // "/\\\\]", "")
            } catch (URISyntaxException ex) {
                Logger.getLogger(classs.getName()).log(Level.WARNING,
                        "Cannot firgue out base path for class with way (2): ", ex);
            }
        }

        // fix to run inside eclipse
        if (basePath.endsWith(File.separator + "lib") || basePath.endsWith(File.separator + "bin")
                || basePath.endsWith("bin" + File.separator) || basePath.endsWith("lib" + File.separator)) {
            basePath = basePath.substring(0, basePath.length() - 4);
        }
        // fix to run inside netbeans
        if (basePath.endsWith(File.separator + "build" + File.separator + "classes")) {
            basePath = basePath.substring(0, basePath.length() - 14);
        }
        // end fix
        if (!basePath.endsWith(File.separator)) {
            basePath = basePath + File.separator;
        }
        return basePath;
    }

0

Bu kod benim için çalıştı:

private static String getJarPath() throws IOException, URISyntaxException {
    File f = new File(LicensingApp.class.getProtectionDomain().().getLocation().toURI());
    String jarPath = f.getCanonicalPath().toString();
    String jarDir = jarPath.substring( 0, jarPath.lastIndexOf( File.separator ));
    return jarDir;
  }

0

Bu kod, programın bir JAR dosyası veya IDE içinde yürütülüp yürütülmediğini tanımlamak için benim için çalıştı:

private static boolean isRunningOverJar() {
    try {
        String pathJar = Application.class.getResource(Application.class.getSimpleName() + ".class").getFile();

        if (pathJar.toLowerCase().contains(".jar")) {
            return true;
        } else {
            return false;
        }
    } catch (Exception e) {
        return false;
    }
}

JAR dosyasının Windows tam yolunu almam gerekirse, bu yöntemi kullanıyorum:

    private static String getPathJar() {
        try {
            final URI jarUriPath =
                    Application.class.getResource(Application.class.getSimpleName() + ".class").toURI();
            String jarStringPath = jarUriPath.toString().replace("jar:", "");
            String jarCleanPath  = Paths.get(new URI(jarStringPath)).toString();

            if (jarCleanPath.toLowerCase().contains(".jar")) {
                return jarCleanPath.substring(0, jarCleanPath.lastIndexOf(".jar") + 4);
            } else {
                return null;
            }
        } catch (Exception e) {
            log.error("Error getting JAR path.", e);
            return null;
        }
    }

CommandLineRunnerUygulamanın her zaman bir konsol görünümü (JAR dosya adında yanlışlıkla çift tıklama) içinde yürütülmesini sağlamak için uygulama kullanarak bir Spring Boot uygulaması ile çalışan benim tam kod, bir sonraki kodu kullanıyorum:

@SpringBootApplication
public class Application implements CommandLineRunner {
    public static void main(String[] args) throws IOException {
        Console console = System.console();

        if (console == null && !GraphicsEnvironment.isHeadless() && isRunningOverJar()) {
            Runtime.getRuntime().exec(new String[]{"cmd", "/c", "start", "cmd", "/k",
                    "java -jar \"" + getPathJar() + "\""});
        } else {
            SpringApplication.run(Application.class, args);
        }
    }

    @Override
    public void run(String... args) {
        /*
        Additional code here...
        */
    }

    private static boolean isRunningOverJar() {
        try {
            String pathJar = Application.class.getResource(Application.class.getSimpleName() + ".class").getFile();

            if (pathJar.toLowerCase().contains(".jar")) {
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            return false;
        }
    }

    private static String getPathJar() {
        try {
            final URI jarUriPath =
                    Application.class.getResource(Application.class.getSimpleName() + ".class").toURI();
            String jarStringPath = jarUriPath.toString().replace("jar:", "");
            String jarCleanPath  = Paths.get(new URI(jarStringPath)).toString();

            if (jarCleanPath.toLowerCase().contains(".jar")) {
                return jarCleanPath.substring(0, jarCleanPath.lastIndexOf(".jar") + 4);
            } else {
                return null;
            }
        } catch (Exception e) {
            return null;
        }
    }
}

-1

Java 7'de yazıyorum ve Oracle'ın çalışma zamanı ile Windows 7'de ve açık kaynak çalışma zamanı ile Ubuntu'da test yapıyorum. Bu, bu sistemler için mükemmel çalışır:

Herhangi bir çalışan jar dosyasının üst dizininin yolu (bu kodu çağıran sınıfın jar arşivinin kendisinin doğrudan bir alt öğesi olduğu varsayılarak):

try {
    fooDir = new File(this.getClass().getClassLoader().getResource("").toURI());
} catch (URISyntaxException e) {
    //may be sloppy, but don't really need anything here
}
fooDirPath = fooDir.toString(); // converts abstract (absolute) path to a String

Yani, foo.jar yolu şöyle olur:

fooPath = fooDirPath + File.separator + "foo.jar";

Yine, bu herhangi bir Mac veya daha eski Windows'da test edilmedi


-1

getProtectionDomainEğer çekirdek java sınıfları bazıları için kavanozu bulmak zorunda olduğunda yaklaşım bazen örneğin çalışmayabilir (örn benim durumda StringBuilder, IBM JDK içinde sınıfından) Ancak aşağıdaki işleri sorunsuz:

public static void main(String[] args) {
    System.out.println(findSource(MyClass.class));
    // OR
    System.out.println(findSource(String.class));
}

public static String findSource(Class<?> clazz) {
    String resourceToSearch = '/' + clazz.getName().replace(".", "/") + ".class";
    java.net.URL location = clazz.getResource(resourceToSearch);
    String sourcePath = location.getPath();
    // Optional, Remove junk
    return sourcePath.replace("file:", "").replace("!" + resourceToSearch, "");
}

URL.getPath () ne düşündüğünü yapmaz. Özel karakterler yüzde olarak kodlanır.
VGR

-1

Bir sınıfın String konumunu almak için başka bir yol var.

URL path = Thread.currentThread().getContextClassLoader().getResource("");
Path p = Paths.get(path.toURI());
String location = p.toString();

Çıktı Dizesi şu şekilde olacaktır:

C:\Users\Administrator\new Workspace\...

Boşluklar ve diğer karakterler işlenmez ve biçimsizdir file:/. Yani kullanımı daha kolay olacak.

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.