Bagaimana cara mendapatkan path file JAR yang sedang berjalan?

580

Kode saya berjalan di dalam file JAR, katakan foo.jar , dan saya perlu tahu, dalam kode tersebut, di folder mana foo.jar berjalan .

Jadi, jika foo.jar ada di dalamnyaC:\FOO\ , saya ingin mendapatkan jalur itu, apa pun direktori kerja saya saat ini.

Thiago Chaves
sumber
Lihat jawaban Fab untuk solusi yang berfungsi saat jalur menyertakan spasi. Juga, perhatikan bahwa beberapa jawaban di bawah ini menjawab pertanyaan dalam judul (path jar), beberapa menjawab pertanyaan itu sendiri (path folder yang berisi jar), dan beberapa menyediakan path ke kelas di dalam file jar.
Andy Thomas
32
Waspadalah saat menggunakan di ANT! ============== Saya sebut String path = SomeClass.class.getProtectionDomain (). GetCodeSource (). GetLocation (). GetPath (); dan dapatkan: /C:/apache-ant-1.7.1/lib/ant.jar Tidak terlalu berguna!
Dino Fancellu
Menarik. Kode asli tempat saya menggunakan ini tidak pernah dijalankan di semut, jadi itu bukan masalah bagi saya.
Thiago Chaves
2
@Dino Fancellu, saya mengalami persis apa yang Anda gambarkan. Bekerja selama dev, gagal saat dibangun untuk jar.
Buddy

Jawaban:

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

Ganti "MyClass" dengan nama kelas Anda.

Jelas, ini akan melakukan hal-hal aneh jika kelas Anda diambil dari lokasi non-file.

Zarkonnen
sumber
43
The toURI()Langkah penting untuk masalah menghindari dengan karakter khusus, termasuk spasi dan plus. Satu kalimat yang benar adalah: return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().toURI()); Menggunakan URLDecodertidak berfungsi untuk banyak karakter khusus. Lihat jawaban saya di bawah untuk perincian lebih lanjut.
ctrueden
4
Catatan: ini mengembalikan path termasuk nama file jar
Buddy
8
Bukankah ini mengarah ke file jar, bukan direktori yang sedang berjalan? Anda harus melakukan pada getParentFile () hasil untuk pekerjaan ini.
FOO
1
Juga, getProtectionDomainadalah nol jika Anda mendapatkan kelas Anda dari stracktrace:val strace = Thread.currentThread().getStackTrace; val path = strace(1).getClass.getProtectionDomain
bbarker
1
Menggunakan metode ini hingga Java 8; menempatkan metode ini di kelas yang ada di Jar eksternal, dimuat melalui jalur kelas, maka jalur jar eksternal akan diberikan sebagai ganti Jar berjalan yang sebenarnya.
Mr00Anderson
189

Solusi terbaik untuk saya:

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

Ini harus menyelesaikan masalah dengan spasi dan karakter khusus.

Hebat
sumber
8
Satu catatan lagi: Ketika memanggil fungsi ini dari Jar, nama jar ditambahkan di akhir untuk saya, oleh karena itu harus menjalankan: path.substring (0, path.lastIndexOf ("/") +1);
will824
11
Saya belum tentu pemisah jalur. Anda harus melakukannya (File baru (jalur)). GetParentFile (). GetPath () sebagai gantinya.
pjz
10
Tidak ada masalah dengan nama file JAR yang ditambahkan di sini. Konversi UTF tampaknya menjadi solusi sempurna dalam kombinasi dengan @Iviggiani ones ( URLDecoder.decode(ClassLoader.getSystemClassLoader().getResource(".").getPath(), "UTF-8");) di Linux. Namun, saya tidak mencoba di Windows.
ubuntudroid
2
Terima kasih, ini memungkinkan saya untuk memuat file eksternal ke JAR saya dengan FileInputStream di Linux dan Windows. Baru saja menambahkan decodedpath di depan nama file ...
giorgio79
11
Hati-hati: tidak disarankan untuk menggunakan URLDecoderuntuk memecahkan kode karakter khusus. Khususnya, karakter seperti +akan didekodekan secara keliru ke spasi. Lihat jawaban saya untuk detailnya.
ctrueden
153

Untuk mendapatkan Fileuntuk diberikan Class, ada dua langkah:

  1. Konversi Classke aURL
  2. Konversi URLke aFile

Penting untuk memahami kedua langkah, dan tidak mengacaukannya.

Setelah Anda memiliki File, Anda dapat menelepon getParentFileuntuk mendapatkan folder yang berisi, jika itu yang Anda butuhkan.

Langkah 1: ClasskeURL

Seperti dibahas dalam jawaban lain, ada dua cara utama untuk menemukan yang URLrelevan dengan a Class.

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

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

Keduanya memiliki pro dan kontra.

The getProtectionDomainPendekatan menghasilkan lokasi dasar kelas (misalnya, berisi file JAR). Namun, ada kemungkinan bahwa kebijakan keamanan Java runtime akan dilemparkan SecurityExceptionsaat memanggil getProtectionDomain(), jadi jika aplikasi Anda perlu dijalankan di berbagai lingkungan, yang terbaik adalah mengujinya di semua lingkungan tersebut.

The getResourcePendekatan menghasilkan path sumber daya URL lengkap dari kelas, dari mana Anda akan perlu melakukan tambahan manipulasi string. Ini mungkin file:jalan, tetapi juga bisa jar:file:atau bahkan sesuatu yang lebih buruk seperti bundleresource://346.fwk2106232034:4/foo/Bar.classketika mengeksekusi dalam kerangka OSGi. Sebaliknya, getProtectionDomainpendekatan menghasilkan file:URL dengan benar bahkan dari dalam OSGi.

Perhatikan bahwa keduanya getResource("")dan getResource(".")gagal dalam pengujian saya, ketika kelas berada dalam file JAR; kedua doa dikembalikan nol. Jadi saya merekomendasikan doa # 2 yang ditunjukkan di atas sebagai gantinya, karena tampaknya lebih aman.

Langkah 2: URLkeFile

Either way, setelah Anda memiliki URL, langkah selanjutnya adalah mengonversi ke a File. Ini adalah tantangannya sendiri; lihat posting blog Kohsuke Kawaguchi tentang hal itu untuk detail lengkap, tetapi singkatnya, Anda dapat menggunakan new File(url.toURI())selama URL benar-benar terbentuk dengan baik.

Terakhir, saya akan sangat tidak suka menggunakan URLDecoder. Beberapa karakter URL, :dan /khususnya, bukan karakter yang disandikan dengan URL. Dari URLDecoder Javadoc:

Diasumsikan bahwa semua karakter dalam string yang disandikan adalah salah satu dari yang berikut: "a" hingga "z", "A" hingga "Z", "0" hingga "9", dan "-", "_", " . ", dan" * ". Karakter "%" diperbolehkan tetapi ditafsirkan sebagai awal dari urutan lolos khusus.

...

Ada dua cara yang memungkinkan dekoder ini dapat menangani string ilegal. Itu bisa meninggalkan karakter ilegal sendirian atau bisa melempar IllegalArgumentException. Pendekatan mana yang diambil oleh decoder diserahkan pada implementasi.

Dalam praktiknya, URLDecoderumumnya tidak melempar IllegalArgumentExceptionseperti terancam di atas. Dan jika path file Anda memiliki ruang yang disandikan %20, pendekatan ini mungkin berfungsi. Namun, jika jalur file Anda memiliki karakter non-alfamerik lain seperti +Anda akan mengalami masalah dengan URLDecodermengatur jalur file Anda.

Kode kerja

Untuk mencapai langkah-langkah ini, Anda mungkin memiliki metode seperti berikut:

/**
 * 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);
}

Anda dapat menemukan metode ini di perpustakaan umum SciJava :

ctrueden
sumber
5
+1; jawaban terbaik saat ini: ini akan mengembalikan jalur menggunakan notasi yang benar untuk OS. (mis. \ untuk windows).
Batsyeba
Mengenai keamanan, saya yakin saya menemukan bahwa Java WebStart tidak mengizinkan ini.
Thorbjørn Ravn Andersen
55

Anda juga bisa menggunakan:

CodeSource codeSource = YourMainClass.class.getProtectionDomain().getCodeSource();
File jarFile = new File(codeSource.getLocation().toURI().getPath());
String jarDir = jarFile.getParentFile().getPath();
Benny Neugebauer
sumber
3
Ini bekerja lebih baik untuk saya, karena itu memberi jalan Jar, bukan kelas!
T30
Bekerja untuk saya juga. Kombinasikan dengan jawaban Fab dan itu menjadi lebih baik!
Danielson Alves Júnior
25

Gunakan ClassLoader.getResource () untuk menemukan URL untuk kelas Anda saat ini.

Sebagai contoh:

package foo;

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

(Contoh ini diambil dari pertanyaan serupa .)

Untuk menemukan direktori, Anda harus membongkar URL secara manual. Lihat tutorial JarClassLoader untuk format URL jar.

Jon Skeet
sumber
File JAR saya dikaburkan, jadi jawaban ini tidak menyelesaikan masalah saya. Tapi saya belum menentukannya dalam pertanyaan, jadi ini masih merupakan jawaban yang valid.
Thiago Chaves
12
Jika dikaburkan, gunakan Test.class.getName () dan lakukan munging yang sesuai.
Jon Skeet
1
@JonSkeet ada begitu banyak masalah dengan jawaban Anda: 1. Tidak akan ada NPEkarena Anda tidak menjawab pertanyaan yang diajukan (jalur ke JAR dir ditanya dan Anda menjawab pertanyaan yang sangat berbeda: jalur ke kelas). 2. Seperti yang ditunjukkan oleh orang lain, dan saya mendapatkan masalah yang sama, itu tidak berfungsi untuk applet. 3. jalan Returned tidak representasi jalan kanonik sama sekali: jar:file:/listener/build/libs/listener-1.0.0-all.jar!/shared/Test.class.
WhiteAngel
1
@WhiteAngel: 1) Baris terakhir dari posting saya menunjukkan bahwa Anda perlu melihat URL dan memilihnya secara terpisah untuk mendapatkan file jar. Saya setuju itu bukan jawaban yang paling lengkap, tapi saya pikir itu tidak terlalu layak untuk diperdebatkan (terutama 10 tahun kemudian ...) 2) Applet tidak disebutkan dalam komentar di sini - anehnya, saya tidak punya waktu untuk melihat semua komentar pada semua jawaban atas pertanyaan yang kebetulan saya posting jawabannya. 3) Sekali lagi, saya menautkan ke format URL jar.
Jon Skeet
2
@WhiteAngel: Apakah ini jawaban terbaik yang pernah saya tulis? Nggak. Apakah seburuk yang Anda bayangkan? Tidak, kurasa tidak. (Terutama dalam hal klaim yang Anda buat di sekitar itu melemparkan NPE, yang tidak.) Saya sarankan Anda menambahkan jawaban Anda sendiri daripada membuat keributan tentang yang ini. Itu akan menjadi pendekatan yang lebih positif.
Jon Skeet
19

Saya terkejut melihat bahwa tidak ada yang baru-baru ini diusulkan untuk digunakan Path. Berikut berikut kutipan: " The Pathclass meliputi berbagai metode yang dapat digunakan untuk memperoleh informasi tentang jalan, elemen akses jalan, mengkonversi jalan untuk bentuk lain, atau ekstrak bagian dari jalan "

Dengan demikian, alternatif yang baik adalah dengan Pathmengajukan keberatan sebagai:

Path path = Paths.get(Test.class.getProtectionDomain().getCodeSource().getLocation().toURI());
mat_boy
sumber
3
Sebagai catatan, Path tersedia mulai di Java 7.
Chris Forrence
15

Satu-satunya solusi yang berfungsi untuk saya di Linux, Mac dan Windows:

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();
}
Dmitry Trofimov
sumber
Ini tidak akan berfungsi. Jika di Linux, metode toUri () akan melempar pengecualian, dan Anda tidak akan mencapai bagian yang lain, untuk linux.
Wilhelm Sorban
9

Saya memiliki masalah yang sama dan saya menyelesaikannya dengan cara itu:

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

Saya harap saya bisa membantu Anda.

Charlie
sumber
Jangan lakukan itu. URL.getPath () tidak mengembalikan nama file dan itu akan gagal dalam banyak keadaan, seperti path file dengan spasi di dalamnya.
VGR
9

Berikut ini peningkatan ke komentar lain, yang menurut saya tidak lengkap untuk spesifik

menggunakan "folder" relatif di luar file .jar (di lokasi yang sama dengan toples):

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"));
Zon
sumber
4
Hati-hati: tidak disarankan untuk menggunakan URLDecoderuntuk memecahkan kode karakter khusus. Khususnya, karakter seperti +akan didekodekan secara keliru ke spasi. Lihat jawaban saya untuk detailnya.
ctrueden
Tidak disarankan menggunakan karakter khusus dalam nama file.
Zon
URLDecoder, terlepas dari namanya, adalah untuk mendekode URL dan membentuk nama dan nilai parameter, bukan URL.
Marquis of Lorne
6

Untuk mendapatkan jalur menjalankan file jar saya telah mempelajari solusi di atas dan mencoba semua metode yang ada perbedaan satu sama lain. Jika kode ini berjalan di Eclipse IDE, mereka semua harus dapat menemukan path file termasuk kelas yang ditunjukkan dan membuka atau membuat file yang ditunjukkan dengan path yang ditemukan.

Tapi itu rumit, ketika menjalankan file jar runnable secara langsung atau melalui baris perintah, itu akan gagal karena path file jar didapat dari metode di atas akan memberikan jalur internal dalam file jar, yang selalu memberikan path sebagai

rsrc: project-name (mungkin saya harus mengatakan bahwa itu adalah nama paket dari file kelas utama - kelas yang ditunjukkan)

Saya tidak dapat mengonversi jalur rsrc: ... ke jalur eksternal, yaitu saat menjalankan file jar di luar Eclipse IDE, ia tidak dapat memperoleh jalur file jar.

Satu-satunya cara yang mungkin untuk mendapatkan jalur menjalankan file jar di luar Eclipse IDE adalah

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

baris kode ini dapat mengembalikan path hidup (termasuk nama file) dari file jar yang sedang berjalan (perhatikan bahwa path kembali bukan direktori kerja), seperti dokumen java dan beberapa orang mengatakan bahwa itu akan mengembalikan path semua file kelas di direktori yang sama, tetapi sebagai pengujian saya jika dalam direktori yang sama menyertakan banyak file jar, itu hanya mengembalikan jalur menjalankan jar (tentang masalah beberapa jalur memang itu terjadi di Eclipse).

phchen2
sumber
java.class.pathdapat multinilai. Satu nilai-nilai itu tentu akan memberikan direktori atau file JAR di mana kelas saat ini berada, tetapi yang mana?
Marquis of Lorne
Saya mengkonfirmasi, saya mencoba solusi lain, tetapi tidak pernah mendapatkan nama file toples. Ini bekerja sangat sederhana! terima kasih - +1
guillaume girod-vitouchkina
5

Jawaban lain tampaknya mengarah ke sumber kode yang merupakan lokasi file Jar yang bukan direktori.

Menggunakan

return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()).getParentFile();
FOO
sumber
Itu bisa berupa direktori, jika Anda memuat kelas Anda dari sistem file, bukan file JAR, misalnya saat debugging.
Marquis of Lorne
4

jawaban yang dipilih di atas tidak berfungsi jika Anda menjalankan tabung Anda dengan mengkliknya dari lingkungan desktop Gnome (bukan dari skrip atau terminal apa pun).

Sebaliknya, saya suka bahwa solusi berikut ini bekerja di mana-mana:

    try {
        return URLDecoder.decode(ClassLoader.getSystemClassLoader().getResource(".").getPath(), "UTF-8");
    } catch (UnsupportedEncodingException e) {
        return "";
    }
lviggiani
sumber
2
Apakah Anda mencobanya di applet, atau aplikasi. diluncurkan menggunakan Java Web Start? Pemahaman saya adalah bahwa itu akan gagal di kedua situasi (bahkan jika aplikasi. Dipercaya).
Andrew Thompson
Solusi ini hanya dapat mengembalikan lokasi "." dalam file JAR, bukan lokasi dari file JAR.
Marquis of Lorne
Hati-hati: tidak disarankan untuk menggunakan URLDecoderuntuk memecahkan kode karakter khusus. Khususnya, karakter seperti +akan didekodekan secara keliru ke spasi. Lihat jawaban saya untuk detailnya.
ctrueden
Di Spring boot, ia akan melemparNullPointerException
Ravi Parekh
Anda akan memilikinya NPEjika tidak ada sumber daya di JAR.
WhiteAngel
3

Sebenarnya ini adalah versi yang lebih baik - yang lama gagal jika nama folder memiliki ruang di dalamnya.

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

Sedangkan untuk gagal dengan applet, Anda biasanya tidak akan memiliki akses ke file lokal. Saya tidak tahu banyak tentang JWS tetapi untuk menangani file lokal mungkin tidak mungkin untuk mengunduh aplikasi.?

pemuda bacup
sumber
Ada beberapa cara untuk memecahkan kode lintasan. Tidak perlu menulis kode Anda sendiri.
Marquis of Lorne
3

Saya mencoba untuk mendapatkan jalur menjalankan jar menggunakan

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

c: \ app> java -jar application.jar

Menjalankan aplikasi jar bernama "application.jar", pada Windows di folder " c: \ app ", nilai variabel "folder" String adalah " \ c: \ app \ application.jar " dan saya mengalami masalah pengujian untuk kebenaran jalan

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

Jadi saya mencoba mendefinisikan "tes" sebagai:

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

untuk mendapatkan path dalam format yang tepat seperti " c: \ app ", bukan " \ c: \ app \ application.jar " dan saya perhatikan bahwa itu berfungsi.

Kelinci Besar
sumber
3

Solusi paling sederhana adalah dengan melewatkan jalur sebagai argumen saat menjalankan toples.

Anda dapat mengotomatiskan ini dengan skrip shell (.bat di Windows, .sh di tempat lain):

java -jar my-jar.jar .

Saya biasa .melewati direktori kerja saat ini.

MEMPERBARUI

Anda mungkin ingin menempel file jar di sub-direktori sehingga pengguna tidak sengaja mengkliknya. Kode Anda juga harus memeriksa untuk memastikan bahwa argumen baris perintah telah disediakan, dan memberikan pesan kesalahan yang baik jika argumen tersebut hilang.

Max Heiber
sumber
3

Saya harus banyak dipusingkan sebelum akhirnya menemukan solusi yang berfungsi (dan singkat).
Ada kemungkinan bahwa jarLocationdisertai dengan awalan seperti file:\atau jar:file\, yang dapat dihapus dengan menggunakan String#substring().

URL jarLocationUrl = MyClass.class.getProtectionDomain().getCodeSource().getLocation();
String jarLocation = new File(jarLocationUrl.toString()).getParent();
Jelle
sumber
2
String path = getClass().getResource("").getPath();

Path selalu merujuk ke sumber daya dalam file jar.

ZZZ
sumber
1
String path itu masih perlu disederhanakan sesuai kebutuhan Anda. String path = new File(getClass().getResource("").getPath()).getParentFile().getParent(); File jarDir = new File(path.substring(5));
ZZZ
4
Keduanya getResource("")dan getResource(".")gagal dalam pengujian saya, ketika kelas berada dalam file JAR; kedua doa dikembalikan nol.
ctrueden
2
Ini melempar NullPointerException.
Marquis of Lorne
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;}

Berfungsi baik di Windows

Denton
sumber
1

Sesuatu yang membuat frustrasi adalah ketika Anda berkembang di Eclipse MyClass.class.getProtectionDomain().getCodeSource().getLocation()mengembalikan /bindirektori yang bagus, tetapi ketika Anda mengkompilasinya ke jar, path menyertakan /myjarname.jarbagian yang memberi Anda nama file ilegal.

Agar kode berfungsi baik dalam ide dan setelah dikompilasi ke stoples, saya menggunakan potongan kode berikut:

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");
}
Alexander
sumber
1

Tidak benar-benar yakin tentang yang lain tetapi dalam kasus saya itu tidak bekerja dengan "jar Runnable" dan saya membuatnya bekerja dengan memperbaiki kode bersama-sama dari jawaban phchen2 dan yang lain dari tautan ini: Bagaimana cara mendapatkan jalur file JAR yang berjalan? Kode:

               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");
Fahad Alkamli
sumber
1

Telah mencoba beberapa solusi di sana tetapi tidak ada yang menghasilkan hasil yang benar untuk kasus (mungkin khusus) bahwa jar runnable telah diekspor dengan "Kemasan perpustakaan eksternal" di Eclipse. Untuk beberapa alasan semua solusi yang didasarkan pada ProtectionDomain menghasilkan null dalam kasus itu.

Dari menggabungkan beberapa solusi di atas saya berhasil mencapai kode kerja berikut:

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);
DragonGamer
sumber
1

Coba ini:

String path = new File("").getAbsolutePath();
Blarzek
sumber
0

Metode ini, dipanggil dari kode dalam arsip, mengembalikan folder tempat file .jar berada. Ini harus bekerja di Windows atau Unix.


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

Berasal dari kode di: Menentukan apakah menjalankan dari JAR

Bacup Lad
sumber
3
"Ini seharusnya bekerja di Windows atau Unix." tetapi akan gagal di semua applet dan setiap aplikasi. diluncurkan menggunakan JWS.
Andrew Thompson
0

Sebutkan bahwa itu hanya dicek Windowstetapi saya pikir ini berfungsi sempurna pada Sistem Operasi lain [ Linux,MacOs,Solaris] :).


Saya memiliki 2 .jar file di direktori yang sama. Saya ingin dari satu .jarfile untuk memulai .jarfile lain yang ada di direktori yang sama.

Masalahnya adalah ketika Anda memulainya dari cmddirektori saat ini system32.


Peringatan!

  • Di bawah ini tampaknya bekerja dengan cukup baik di semua tes yang telah saya lakukan bahkan dengan nama folder ;][[;'57f2g34g87-8+9-09!2#@!$%^^&()atau ()%&$%^@# berfungsi dengan baik.
  • Saya menggunakan ProcessBuilderdengan di bawah ini sebagai berikut:

🍂 ..

//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;
    }
GOXR3PLUS
sumber
0

Kode ini berfungsi untuk saya:

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;
  }
John Lockwood
sumber
0

Kode ini berfungsi bagi saya untuk mengidentifikasi apakah program sedang dijalankan di dalam file JAR atau IDE:

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

Jika saya perlu mendapatkan path Windows penuh file JAR saya menggunakan metode ini:

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

Kode lengkap saya bekerja dengan aplikasi Spring Boot menggunakan CommandLineRunnerimplementasi, untuk memastikan bahwa aplikasi selalu dieksekusi dalam tampilan konsol (Klik ganda karena kesalahan dalam nama file JAR), saya menggunakan kode berikut:

@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;
        }
    }
}
Jairo Martínez
sumber
-1

Saya menulis di Java 7, dan menguji di Windows 7 dengan runtime Oracle, dan Ubuntu dengan runtime open source. Ini berfungsi sempurna untuk sistem itu:

Path untuk direktori induk dari setiap file jar yang sedang berjalan (dengan asumsi kelas yang memanggil kode ini adalah anak langsung dari arsip jar itu sendiri):

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

Jadi, jalan foo.jar adalah:

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

Sekali lagi, ini tidak diuji pada Mac atau Windows yang lebih lama

sudoBen
sumber
-1

The getProtectionDomainPendekatan mungkin tidak bekerja kadang-kadang misalnya ketika Anda harus menemukan jar untuk beberapa kelas java inti (misalnya dalam kasus saya StringBuilderkelas dalam IBM JDK), karya namun berikut mulus:

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, "");
}
Vasu
sumber
URL.getPath () tidak melakukan apa yang Anda pikirkan. Setiap karakter khusus akan dikodekan persen.
VGR
-1

Saya punya cara lain untuk mendapatkan lokasi String dari sebuah kelas.

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

String keluaran akan memiliki bentuk

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

Spasi dan karakter lain ditangani, dan dalam bentuk tanpa file:/. Jadi akan lebih mudah digunakan.

NoSegfault
sumber